home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / hardware / h550_driver / h550.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  71.1 KB  |  3,076 lines

  1. /*
  2.  * Copyright (C) 1986, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /**************************************************************************
  18.  *  Streams driver for the Comtrol Hostess 550 serial port controller
  19.  *
  20.  *  This driver controls up to 4 Controller, each with 8 independent
  21.  *  ports to use. Each port on a controller is capable of working as
  22.  *  a serial port, Modem or Flow control and this module must determine
  23.  *  how each port is being used. For this reason, we use the device's
  24.  *  Minor Number to determine:
  25.  *            - Controller number
  26.  *            - Port Number within that controller
  27.  *            - Whether the port is being used as Modem 
  28.  *              or Flow Control.
  29.  *
  30.  *  There are 96 Minor device numbers, each assigned to a unique
  31.  *  /dev/ttyxxx file (32 ports, each can be set as serial port, Modem
  32.  *  or Flow control, hence 32 x 3 = 96 minor device number needed).
  33.  *
  34.  *  These Minor numbers are as follow:
  35.  *
  36.  *    Minor number    Controller    Description
  37.  *    ------------    ----------    -----------
  38.  *     0 - 7        0        Serial Ports
  39.  *     8 - 15        1        Serial Ports
  40.  *    16 - 23        2        Serial Ports
  41.  *    24 - 31        3        Serial Ports
  42.  *
  43.  *    32 - 39        0        Modem Ports
  44.  *    40 - 47        1        Modem Ports
  45.  *    48 - 55        2        Modem Ports
  46.  *    56 - 63        3        Modem Ports
  47.  *
  48.  *    64 - 71        0        Flow Control Ports
  49.  *    72 - 79        1        Flow Control Ports
  50.  *    80 - 87        2        Flow Control Ports
  51.  *    88 - 95        3        Flow Control Ports
  52.  *
  53.  *
  54.  * $Revision: 1.00 $
  55.  ****************************************************************************
  56. */
  57.  
  58. #include "sys/cmn_err.h"
  59. #include "sys/debug.h"
  60. #include "sys/errno.h"
  61. #include "sys/file.h"
  62. #include "sys/param.h"
  63. #include "sys/signal.h"
  64. #include "sys/stream.h"
  65. #include "sys/strids.h"
  66. #include "sys/strmp.h"
  67. #include "sys/stropts.h"
  68. #include "sys/stty_ld.h"
  69. #include "sys/sysinfo.h"
  70. #include "sys/sysmacros.h"
  71. #include "sys/systm.h"
  72. #include "sys/termio.h"
  73. #include "sys/types.h"
  74. #include "sys/cpu.h"
  75. #include "sys/user.h"
  76. #include "sys/sema.h"
  77. #include "sys/ddi.h"
  78. #include "sys/edt.h"
  79. #include "sys/pio.h"
  80. #include "sys/eisa.h"
  81. #include "sys/cred.h"
  82.  
  83. #include "./h550.h"
  84.  
  85. #define STRID_h550   9037    /*****  should be moved to strids.h later  *****/
  86.  
  87. /*    for debugging    */
  88. #ifdef DEBUG
  89. static h550debug = 0;
  90. #endif 
  91.  
  92. /*    'extern'  stuff ...  */
  93. extern int kdebugbreak;
  94. extern struct stty_ld def_stty_ld;
  95. extern int duart_rsrv_duration;         /* send input this often */
  96.  
  97. int chars_rcvd;
  98. int chars_xmt;
  99.  
  100. /* default cflags */
  101. #define DEF_CFLAG         ((ushort_t)(CREAD | def_stty_ld.st_cflag))
  102. #define    CNTRL_A        '\001'
  103.  
  104. /*   Misc. defines ..  */
  105. #define MIN_RMSG_LEN    4               /* minimum buffer size */
  106. #define MAX_RMSG_LEN    2048            /* largest msg allowed */
  107. #define XOFF_RMSG_LEN   256             /* send XOFF here */
  108. #define MAX_RBUF_LEN    1024
  109. #define MAX_RSRV_CNT    3               /* continue input timer this long */
  110.  
  111. #define INB(x)     (*(volatile uchar_t *)(x))
  112. #define OUTB(x,y)  (*(volatile uchar_t *)(x) = (y))
  113.  
  114. #define EISA_NUM_SLOTS  4
  115. #define NUMMINOR        8               /* must be (2**n) */
  116. #define PORT(dev)       ((dev) & (NUMMINOR - 1))
  117. #define MODEM(dev)      ((dev) & (NUMMINOR * 4))
  118. #define FLOW_MODEM(dev) ((dev) & (NUMMINOR * 8))
  119.  
  120. #define SEND_XON        1
  121. #define SEND_XOFF       0
  122. #define IGNORE_IXOFF    1
  123.  
  124. /*    all the data in a given Device Minor Number   */
  125. typedef struct minorNumInfo {
  126.     short    m_ctl;     /*   controller number             */
  127.     short    m_port;    /*   port in the controller        */
  128.     short    m_modem;   /*   1 = operating as Modem        */
  129.     short    m_flow;    /*   1 = operating as Flow Control */
  130. } minorNumInfo_t;
  131.  
  132.  
  133. /*********************************************************************
  134.  *                Port's static data                           *
  135.  *********************************************************************
  136.  *    We keep track of these data for each port on a controller.
  137.  *    Note that there might be 4 controller, each having 8 ports.
  138.  *    (total of 32 ports can be available).     
  139.  */
  140. typedef struct h550port {
  141.     /* hardware address */
  142.     uchar_t  dp_ctl;                 /* Controller's number  */ 
  143.     uchar_t    dp_index;        /* port number */
  144.     caddr_t    port_addr;        /* port's address */
  145.  
  146.     int    xmitlev;        /* Transmit level */
  147.     int    open;            /* Number of open FIFO positions */
  148.  
  149.     uchar_t    dp_rsrv_cnt;        /* input timer count */
  150.     int    dp_rsrv_duration;    /* input timer */
  151.  
  152.     uint_t    dp_state;        /* current state */
  153.  
  154.     struct termio dp_termio;
  155.     queue_t    *dp_rq, *dp_wq;        /* our queues */
  156.     mblk_t    *dp_rmsg, *dp_rmsge;    /* current input message, head/tail */
  157.     int    dp_rmsg_len;        /* current input message length */
  158.     int    dp_rbsize;        /* recent input message length */
  159.     mblk_t    *dp_rbp;        /* current input buffer */
  160.     mblk_t    *dp_wbp;        /* current output buffer */
  161.  
  162.     int    dp_tid;            /* (recent) output delay timer ID */
  163.  
  164.     int    dp_fe, dp_over;        /* framing/overrun errors counts */
  165.     int    dp_allocb_fail;        /* losses due to allocb() failures */
  166. } h550port_t;
  167.  
  168. /*    dp_termio  various fields... */
  169. #define dp_iflag dp_termio.c_iflag      /* use some of the bits (see below) */
  170. #define dp_cflag dp_termio.c_cflag      /* use all of the standard bits */
  171. #define dp_line  dp_termio.c_line       /* line discipline */
  172. #define dp_cc    dp_termio.c_cc         /* control characters */
  173.  
  174. /* bits in dp_state */
  175. #define DP_ISOPEN       0x00000001      /* device is open */
  176. #define DP_WOPEN        0x00000002      /* waiting for carrier */
  177. #define DP_DCD          0x00000004      /* we have carrier */
  178. #define DP_TIMEOUT      0x00000008      /* delaying */
  179. #define DP_BREAK        0x00000010      /* breaking */
  180. #define DP_BREAK_QUIET  0x00000020      /* finishing break */
  181. #define DP_TXSTOP       0x00000040      /* output stopped by received XOFF */
  182. #define DP_LIT          0x00000080      /* have seen literal character */
  183. #define DP_BLOCK        0x00000100      /* XOFF sent because input full */
  184. #define DP_TX_TXON      0x00000200      /* need to send XON */
  185. #define DP_TX_TXOFF     0x00000400      /* need to send XOFF */
  186. #define DP_SE_PENDING   0x00000800      /* buffer alloc event pending */
  187.  
  188. #define DP_EXTCLK       0x10000000      /* external clock mode */
  189. #define DP_MANCTRL      0x20000000      /* Manual control of RTS & DTR */
  190. #define DP_FLOW         0x40000000      /* do hardware flow control */
  191. #define DP_MODEM        0x80000000      /* modem device */
  192.  
  193. #define DP_BREAK_ON     0x00010000      /* receiving break */
  194. #define DP_CTS          0x00020000      /* CTS on */
  195.  
  196. /*************************************************************************
  197.  *             Controllers Data/Status Array                            *
  198.  *************************************************************************
  199.  *    This Array has an entry for each Controller we support.
  200.  *    All Driver routines deal with one of these entries. The 
  201.  *    entry itself keeps data/status for the Controller's base address,
  202.  *    IRQ assigned, and contains Port info/data for each of 8 ports
  203.  *    of the controller.
  204.  */
  205. typedef struct edrvinfo {
  206.         caddr_t e_addr[NBASE];
  207.         int     e_dmachan;
  208.         int     e_irq;
  209.         int     e_numports;
  210.         int     e_intmask;
  211.         h550port_t   e_ports[MAX_PORTS];
  212. }  edrvinfo_t;
  213.  
  214. static edrvinfo_t    einfo[EISA_NUM_SLOTS];   /*  Controller Array   */
  215.  
  216.  
  217. /*
  218.  *   Driver Entry routines in this file
  219.  */
  220. struct cred;
  221. static void h550_rsrv(queue_t *);
  222. static int  h550_open(queue_t *, dev_t *, int, int, struct cred *);
  223. static int  h550_close(queue_t *, int, struct cred *);
  224. static void h550_poll();
  225. static int  h550_wput(queue_t *, mblk_t *);
  226.  
  227. static void    h550_con(h550port_t *);
  228. static void    h550_coff(h550port_t *);
  229. static void    h550_flushw(h550port_t *);
  230. static void    h550_flushr(struct h550port *);
  231. static mblk_t *h550_getbp(h550port_t *, uint_t);
  232. static void    h550_rx(h550port_t *);
  233. static void    h550_tx(h550port_t *, int);
  234.  
  235.  
  236. /*
  237.  **************************************************************** 
  238.  *  Unix STREAM device driver required structures and data.     *
  239.  ****************************************************************
  240.  *  The required structure are:                            *    
  241.  *     - Module Info                            *
  242.  *     - qinit for Read and Write (In and Out) queues           *
  243.  *     - streamtab structure to point to all above              *
  244.  *  Refer to your Unix Device Driver manual for more info       *
  245.  **************************************************************** 
  246. */
  247.  
  248. /*   Module Info structure   */
  249. static struct module_info h550m_info = 
  250. {
  251.     STRID_h550,            /* module ID */
  252.     "h550",                /* module name */
  253.     0,                /* minimum packet size */
  254.     INFPSZ,                /* maximum packet size--infinite */
  255.     128,                /* hi-water mark */
  256.     16,                /* lo-water mark */
  257. };
  258.  
  259. /*  'qinit' for  Input queue (Read queue)    */
  260. static struct qinit h550rinit = {
  261.     NULL, (int (*)())h550_rsrv, h550_open, h550_close, NULL, &h550m_info, NULL
  262. };
  263.  
  264. /*  'qinit' for Output queue (Write queue)   */
  265. static struct qinit h550winit = {
  266.     h550_wput, NULL, NULL, NULL, NULL, &h550m_info, NULL
  267. };
  268.  
  269. /*  'streamtab' for the drive (put all above together)  */
  270. struct streamtab h550info = {
  271.     &h550rinit, &h550winit, NULL, NULL
  272. };
  273.  
  274. /*
  275.  ****************************************************
  276.  *         EISA bus interface data/variables        *
  277.  **************************************************** 
  278. */
  279.  
  280. /*
  281.  *    EISA interrupt mask for each controller. Each bit
  282.  *    represents an Interrupt number requested. We use  
  283.  *    the following Interrupt numbers (IRQs):       
  284.  *         Ctrl No    IRQ no      Mask
  285.  *         -------    ------      ------
  286.  *              0      3       0x0008
  287.  *        1      4       0x0010
  288.  *        2      5      0x0020
  289.  *        3     10      0x0400
  290.  *
  291.  *    Refer to:  User's guide to Comtrol Hostess 550
  292.  *         IRIX Dev.Driver programing Guide (EISA Device Driver)
  293.  */ 
  294.  
  295. static int  IRQ_MASK[] = {0x0008, 0x0010, 0x0020, 0x0400};
  296.  
  297. /*
  298.  *   Specifying Interrupt Handling routines for each IRQ specified
  299.  *   above (see IRQ_MASKs). See edtinit routine for EISA bus for more info.
  300.  */ 
  301.  
  302. /*  used in order to pass controller number to the routine  */
  303. typedef void    (* intentry_t)();
  304. void h550_poll_0(){h550_poll(0);}
  305. void h550_poll_1(){h550_poll(1);}
  306. void h550_poll_2(){h550_poll(2);}
  307. void h550_poll_3(){h550_poll(3);}
  308.  
  309. /*   interrupt handling table (one for each controller)  */
  310. intentry_t      intentrypnt[N_ADAPTERS] = {
  311.         h550_poll_0,
  312.         h550_poll_1,
  313.         h550_poll_2,
  314.         h550_poll_3,
  315. };
  316.  
  317. int h550devflag = 0;
  318.  
  319. static fifo_size = 16;        /* on chip transmit FIFO size */
  320.  
  321. static void ShowPortInfo(ushort_t, h550port_t *);
  322. static void getMinorInfo(minor_t, minorNumInfo_t *);
  323.  
  324. static void comtrol_h550_break(h550port_t *, int);
  325. static void comtrol_h550_config(h550port_t *, ushort_t, struct termio *);
  326. static int  comtrol_h550_getchar(h550port_t *);
  327. static void comtrol_h550_iflow(h550port_t *, int, int);
  328. static void comtrol_h550_putchar(h550port_t *, uchar_t);
  329. static int  comtrol_h550_start_rx(h550port_t *);
  330. static void comtrol_h550_start_tx(h550port_t *);
  331. static void comtrol_h550_stop_rx(h550port_t *, int);
  332. static void comtrol_h550_stop_tx(h550port_t *);
  333. static int  comtrol_h550_txrdy(h550port_t *);
  334.  
  335. static int h550_baudtbl[] = {
  336.     0,                  /* B0 */
  337.     2304,               /* 50 */
  338.     1536,               /* 75 */
  339.     1047,               /* 110 */
  340.     857,                /* 134 */
  341.     768,                /* 150 */
  342.     0,                  /* 200 */
  343.     384,                /* 300 */
  344.     192,                /* 600 */
  345.     96,                 /* 1200 */
  346.     64,                 /* 1800 */
  347.     48,                 /* 2400 */
  348.     24,                 /* 4800 */
  349.     12,                 /* 9600 */
  350.     6,                  /* exta - 19200 */
  351.     3                   /* extb - 38400 */
  352. };
  353.  
  354.  
  355.  
  356. /**************************************************************************
  357.  *                  h 5 5 0 _ r c l r                                     *
  358.  **************************************************************************
  359.  *
  360.  *     Name:    h550_rclr
  361.  *
  362.  *     Description:
  363.  *        Gobble any waiting input for a port.
  364.  *        Should only be called when safe from interrupts.
  365.  *
  366.  *     Returns:
  367.  *
  368.  **************************************************************************
  369. */
  370. static void
  371. h550_rclr( h550port_t   *dp )
  372. {
  373.     int c;
  374.  
  375.     #ifdef DEBUG2
  376.     cmn_err(CE_NOTE,"rclr: Read clear routine");
  377.     #endif /* DEBUG2 */
  378.  
  379.     while ((c = comtrol_h550_getchar(dp)) != -1) {
  380.     }
  381. }
  382.  
  383.  
  384. /**************************************************************************
  385.  *                  h 5 5 0 _ z a p                                       *
  386.  **************************************************************************
  387.  *
  388.  *     Name:    h550_zap  
  389.  *
  390.  *     Description:
  391.  *              Shut down a port.                      
  392.  *              Should only be called when safe from interrupts.
  393.  *
  394.  *     Returns:
  395.  *
  396.  **************************************************************************
  397. */
  398.  
  399. static void
  400. h550_zap( h550port_t *dp, int hup ) 
  401. {
  402.  
  403. #ifdef DEBUG2
  404.     cmn_err(CE_NOTE,"Zap routine");
  405. #endif /* DEBUG2 */
  406.  
  407.     h550_flushw(dp);            /* forget pending output */
  408.  
  409.     comtrol_h550_stop_rx(dp, hup);
  410.     comtrol_h550_stop_tx(dp);
  411.  
  412.     h550_rclr(dp);
  413. }
  414.  
  415. /**************************************************************************
  416.  *                  h 5 5 0 _ d e l a y                                   *
  417.  **************************************************************************
  418.  *
  419.  *     Name:    h550_delay
  420.  *
  421.  *     Description:
  422.  *              Finish a delay for a port.
  423.  *
  424.  *     Returns:
  425.  *
  426.  **************************************************************************
  427. */
  428.  
  429.  
  430. static void
  431. h550_delay( h550port_t *dp )
  432. {
  433.     int s;
  434.  
  435.     s = LOCK_PORT(dp);
  436.  
  437. #ifdef DEBUG2
  438.     cmn_err(CE_NOTE,"Delay routine");
  439. #endif /* DEBUG2 */
  440.  
  441.     if ((dp->dp_state & (DP_BREAK | DP_BREAK_QUIET)) != DP_BREAK) {
  442.  
  443.         dp->dp_state &= ~(DP_TIMEOUT | DP_BREAK | DP_BREAK_QUIET);
  444.         comtrol_h550_start_tx(dp);    /* resume output */
  445.  
  446.     } 
  447.     else {                /* unless need to quiet break */
  448.         comtrol_h550_break(dp, 0);
  449.         dp->dp_state |= DP_BREAK_QUIET;
  450.         dp->dp_tid = STREAMS_TIMEOUT(h550_delay, (caddr_t)dp, HZ/20);
  451.     }
  452.  
  453.     UNLOCK_PORT(dp, s);
  454. }
  455.  
  456.  
  457.  
  458. /**************************************************************************
  459.  *                         h 5 5 0 _ r s r v _ t i m e r                  *
  460.  **************************************************************************
  461.  *
  462.  *     Name:    h550_rsrv_timer
  463.  *
  464.  *     Description:
  465.  *        Heartbeat to send input up stream.
  466.  *        This is used to reduced the large cost of trying to 
  467.  *        send each input byte upstream by itself.
  468.  *
  469.  *     Returns:
  470.  *
  471.  **************************************************************************
  472. */
  473. static void
  474. h550_rsrv_timer( h550port_t    *dp )
  475. {
  476.     int s;
  477.  
  478.     s = LOCK_PORT(dp);
  479.  
  480. #ifdef DEBUG2
  481.     cmn_err(CE_NOTE,"Read service timer routine");
  482. #endif /* DEBUG2 */
  483.  
  484.     if (--dp->dp_rsrv_cnt)
  485.         (void)STREAMS_TIMEOUT(h550_rsrv_timer, (caddr_t)dp, 
  486.                       dp->dp_rsrv_duration);
  487.  
  488.     if (dp->dp_state & DP_ISOPEN && canenable(dp->dp_rq))
  489.         qenable(dp->dp_rq);
  490.  
  491.     UNLOCK_PORT(dp, s);
  492. }
  493.  
  494.  
  495. /**************************************************************************
  496.  *                         h 5 5 0 _ f l u s h w                          *
  497.  **************************************************************************
  498.  *
  499.  *     Name:    h550_flushw      
  500.  *
  501.  *     Description:
  502.  *              Flush output for a port.              
  503.  *              Should only be called when safe from Interrupts.    
  504.  *
  505.  *     Returns:
  506.  *
  507.  **************************************************************************
  508. */
  509. static void
  510. h550_flushw( h550port_t *dp )
  511. {
  512.  
  513. #ifdef DEBUG2
  514.     cmn_err(CE_NOTE,"Flush write routine");
  515. #endif /* DEBUG2 */
  516.  
  517.     if ((dp->dp_state & (DP_TIMEOUT | DP_BREAK | DP_BREAK_QUIET))
  518.         == DP_TIMEOUT) 
  519.     {
  520.         untimeout(dp->dp_tid);        /* forget stray timeout */
  521.         dp->dp_state &= ~DP_TIMEOUT;
  522.     }
  523.  
  524.     freemsg(dp->dp_wbp);
  525.     dp->dp_wbp = NULL;
  526. }
  527.  
  528. /**************************************************************************
  529.  *                         h 5 5 0 _ f l u s h r                          *
  530.  **************************************************************************
  531.  *
  532.  *     Name:    h550_flushr      
  533.  *
  534.  *     Description:
  535.  *              Flush input for a port.              
  536.  *              Should only be called when safe from Interrupts.    
  537.  *
  538.  *     Returns:
  539.  *
  540.  **************************************************************************
  541. */
  542. static void
  543. h550_flushr( h550port_t *dp )
  544. {
  545.  
  546. #ifdef DEBUG2
  547.     cmn_err(CE_NOTE,"Flush read routine");
  548. #endif /* DEBUG2 */
  549.  
  550.     freemsg(dp->dp_rmsg);
  551.     dp->dp_rmsg = NULL;
  552.     dp->dp_rmsg_len = 0;
  553.     freemsg(dp->dp_rbp);
  554.     dp->dp_rbp = NULL;
  555.  
  556.     qenable(dp->dp_rq);            /* turn input back on */
  557. }
  558.  
  559. /**************************************************************************
  560.  *                         h 5 5 0 _ save                                 *
  561.  **************************************************************************
  562.  *
  563.  *     Name:    h550_save        
  564.  *
  565.  *     Description:
  566.  *              Save a message on our write queue and start
  567.  *              the output interrupt if necessary.
  568.  *
  569.  *     Returns:
  570.  *
  571.  **************************************************************************
  572. */
  573. static int
  574. h550_save(h550port_t *dp, 
  575.       queue_t    *wq, 
  576.       mblk_t     *bp )
  577. {
  578.     volatile caddr_t addr;
  579.     uchar_t        b;
  580.  
  581.  
  582. #ifdef DEBUG2
  583.     cmn_err(CE_NOTE,"Save message routine");
  584. #endif /* DEBUG2 */
  585.  
  586.     putq(wq, bp);                /* save the message */
  587.  
  588.     addr = dp->port_addr;
  589.     b = INB(addr+IER);
  590.  
  591.     if ( !(b & ETBEI) )
  592.         comtrol_h550_start_tx(dp);    /* start TX only if we must */
  593. }
  594.  
  595.  
  596. /**************************************************************************
  597.  *                         h 5 5 0 _ tcgeta                               *
  598.  **************************************************************************
  599.  *
  600.  *     Name:    h550_tcgeta 
  601.  *
  602.  *     Description:
  603.  *              Get current tty parameters.
  604.  *
  605.  *     Returns:
  606.  *
  607.  **************************************************************************
  608. */
  609.  
  610. void
  611. h550_tcgeta( queue_t       *wq,
  612.          mblk_t        *bp,
  613.          struct termio *p )
  614. {
  615.  
  616. #ifdef DEBUG2
  617.     cmn_err(CE_NOTE,"Get tty parameters routine");
  618. #endif /* DEBUG2 */
  619.  
  620.     *STERMIO(bp) = *p;
  621.  
  622.     bp->b_datap->db_type = M_IOCACK;
  623.     qreply(wq, bp);
  624. }
  625.  
  626.  
  627.  
  628. /**************************************************************************
  629.  *                         h 5 5 0 _ tcset                                *
  630.  **************************************************************************
  631.  *
  632.  *     Name:    h550_tcset 
  633.  *
  634.  *     Description:
  635.  *              Set tty parameters.
  636.  *
  637.  *     Returns:
  638.  *
  639.  **************************************************************************
  640. */
  641.  
  642. static void
  643. h550_tcset( h550port_t *dp,
  644.         mblk_t     *bp )
  645.     
  646. {
  647.     ushort_t cflag;
  648.     struct iocblk *iocp;
  649.     struct termio *tp;
  650.  
  651. #ifdef DEBUG2
  652.     cmn_err(CE_NOTE,"Set tty parameters routine");
  653. #endif /* DEBUG2 */
  654.  
  655.     iocp = (struct iocblk *)bp->b_rptr;
  656.     tp = STERMIO(bp);
  657.  
  658.     cflag = tp->c_cflag;
  659.  
  660.     if (dp->dp_state & DP_MODEM) {
  661.                 /*
  662.                  * On modem ports, only super-user can change CLOCAL.
  663.                  * Otherwise, fail to do so silently for historic reasons.
  664.                  */
  665.                 if (((dp->dp_cflag & CLOCAL) ^ (cflag & CLOCAL)) && !suser()) {
  666.                         u.u_error = 0;
  667.                         cflag &= ~CLOCAL;
  668.                         cflag |= dp->dp_cflag & CLOCAL;
  669.                 }
  670.  
  671.     }
  672.  
  673.     comtrol_h550_config(dp, cflag, tp);
  674.  
  675.     tp->c_cflag = dp->dp_cflag;    /* tell line discipline the results */
  676.  
  677.     iocp->ioc_count = 0;
  678.     bp->b_datap->db_type = M_IOCACK;
  679. }
  680.  
  681.  
  682. /**************************************************************************
  683.  *                         h550_i_ioctl                                      *
  684.  **************************************************************************
  685.  *
  686.  *     Name:    h550_i_ioctl
  687.  *
  688.  *     Description:
  689.  *        Interrupt - Process an IOCTL. This function processes
  690.  *        those IOCTLs that must be done by the output interrupt.
  691.  *
  692.  *     Returns:
  693.  *
  694.  **************************************************************************
  695. */
  696.  
  697. static void
  698. h550_i_ioctl( h550port_t *dp,
  699.           mblk_t     *bp )
  700. {
  701.     struct iocblk *iocp;
  702.  
  703. #ifdef DEBUG2
  704.     cmn_err(CE_NOTE,"Interrupt process routine");
  705. #endif /* DEBUG2 */
  706.  
  707.     iocp = (struct iocblk *)bp->b_rptr;
  708.  
  709.     switch (iocp->ioc_cmd) {
  710.      
  711.       case TCSBRK:
  712.  
  713.         if (!*(int *)bp->b_cont->b_rptr) {
  714.  
  715.             dp->dp_state |= DP_TIMEOUT | DP_BREAK;
  716.             comtrol_h550_break(dp, 1);
  717.             dp->dp_tid = STREAMS_TIMEOUT(h550_delay, (caddr_t)dp, HZ/4);
  718.         }
  719.  
  720.         iocp->ioc_count = 0;
  721.         bp->b_datap->db_type = M_IOCACK;
  722.         break;
  723.  
  724.       case TCSETAF:
  725.  
  726.         h550_tcset(dp, bp);
  727.         h550_flushr(dp);
  728.         (void)putctl1(dp->dp_rq->q_next, M_FLUSH, FLUSHR);
  729.         break;
  730.  
  731.       case TCSETA:
  732.       case TCSETAW:
  733.  
  734.         h550_tcset(dp, bp);
  735.         break;
  736.  
  737.       case TCGETA:
  738.  
  739.         h550_tcgeta(dp->dp_wq, bp, &dp->dp_termio);
  740.         return;
  741.  
  742.       default:
  743.  
  744.         ASSERT(0);
  745.     }
  746.  
  747.     putnext(dp->dp_rq, bp);
  748. }
  749.  
  750.  
  751. #ifdef DEBUG2
  752.  
  753.  
  754. /**************************************************************************
  755.  *                         d u m p _ d p                                  *
  756.  **************************************************************************
  757.  *
  758.  *     Name:    dump_dp
  759.  *
  760.  *     Description:
  761.  *        Prints out a port's info
  762.  *
  763.  *     Returns:
  764.  *
  765.  **************************************************************************
  766. */
  767. static void
  768. dump_dp( h550port_t    *dp )
  769. {
  770.     qprintf("Ctl %d, Port %d\n", dp->dp_ctl, dp->dp_index);
  771.     qprintf("State: ");
  772.     if (dp->dp_state & DP_ISOPEN)
  773.         qprintf("ISOPEN ");
  774.     if (dp->dp_state & DP_WOPEN)
  775.         qprintf("WOPEN ");
  776.     if (dp->dp_state & DP_DCD)
  777.         qprintf("DCD ");
  778.     if (dp->dp_state & DP_TIMEOUT)
  779.         qprintf("TIMEOUT ");
  780.     if (dp->dp_state & DP_BREAK)
  781.         qprintf("BREAK ");
  782.     if (dp->dp_state & DP_BREAK_QUIET)
  783.         qprintf("BREAK_QUIET ");
  784.     if (dp->dp_state & DP_TXSTOP)
  785.         qprintf("TXSTOP ");
  786.     if (dp->dp_state & DP_LIT)
  787.         qprintf("LIT ");
  788.     if (dp->dp_state & DP_BLOCK)
  789.         qprintf("BLOCK ");
  790.     if (dp->dp_state & DP_TX_TXON)
  791.         qprintf("TX_TXON ");
  792.     if (dp->dp_state & DP_TX_TXOFF)
  793.         qprintf("TX_TXOFF ");
  794.     if (dp->dp_state & DP_SE_PENDING)
  795.         qprintf("SE_PENDING ");
  796.     if (dp->dp_state & DP_EXTCLK)
  797.         qprintf("EXTCLK ");
  798.     if (dp->dp_state & DP_FLOW)
  799.         qprintf("FLOW ");
  800.     if (dp->dp_state & DP_MODEM)
  801.         qprintf("MODEM ");
  802.     if (dp->dp_state & DP_BREAK_ON)
  803.         qprintf("BREAK_ON ");
  804.     if (dp->dp_state & DP_CTS)
  805.         qprintf("CTS ");
  806.     qprintf("\n");
  807.  
  808.     qprintf("Framing errors: %d, Overruns: %d, Alloc failed: %d\n", 
  809.         dp->dp_fe, dp->dp_over, dp->dp_allocb_fail);
  810. }
  811. #endif
  812.  
  813. /*********************************************************************
  814.  *        h 5 5 0 _ g e t p o r t s 
  815.  *********************************************************************
  816.  *
  817.  *   Name:       h550_getports
  818.  *
  819.  *   Description:
  820.  *
  821.  *        Returns the number of valid ports on a controller.
  822.  *      The base address of the port #0 is given. This routine 
  823.  *      Outputs/Inputs from each port and if expected value is read
  824.  *      then will assume the port is ok.
  825.  *
  826.  *   Returns:
  827.  *        Number of working ports.
  828.  **********************************************************************
  829. */
  830.  
  831. static int 
  832. h550_getports( caddr_t    baseaddr,
  833.            int      max_ports )
  834. {
  835.     register int i, ok_ports;
  836.     caddr_t  addr;
  837.  
  838.     ok_ports = 0;
  839.     addr     = baseaddr;
  840.  
  841.     for ( i = 0; i < max_ports; i++ ) {
  842.  
  843.         OUTB(addr+IER,0x00);
  844.         OUTB(addr+LCR,0x80);
  845.         OUTB(addr+DLM,0xff);
  846.         OUTB(addr+LCR,0x00);
  847.  
  848.         if (INB(addr+IER) == 0) {
  849.         ok_ports++;
  850.         addr += 8;
  851.     }
  852.     else    break;
  853.     }
  854.     
  855.  
  856.     #ifdef DEBUG2
  857.     cmn_err(CE_DEBUG2,"getports: Found %d ports\n", ok_ports);
  858.     #endif /* DEBUG2 */
  859.  
  860.     return(ok_ports);
  861. }
  862.  
  863.  
  864. /**************************************************************************
  865.  *                      h 5 5 0 _ s e t a d d r                           *
  866.  **************************************************************************
  867.  *
  868.  *     Name:           h550_setaddr
  869.  *
  870.  *     Description:
  871.  *        This routine sets the addresses of all ports for 
  872.  *        a given Controller.
  873.  *
  874.  *     Returns:  
  875.  *
  876.  **************************************************************************
  877. */
  878.  
  879. static 
  880. h550_setaddr( caddr_t  baseaddr, 
  881.           int      ports,
  882.           int      ctrl )
  883. {
  884.         register int i;
  885.     caddr_t  addr;
  886.     h550port_t  *dp;
  887.  
  888.     dp   = &einfo[ctrl].e_ports[0];
  889.     addr = baseaddr;
  890.  
  891.          cmn_err(CE_NOTE,"Baseaddr = 0x%x\n", baseaddr);
  892.     cmn_err(CE_NOTE,"Ctrl = %d,  Ports = %d\n", ctrl, ports);
  893.  
  894.         for (i=0; i < ports; i++) {
  895.         dp[i].port_addr = addr;
  896.         cmn_err(CE_NOTE, "Ctrl = 0x%x, port = %d,  port_addr = 0x%x\n",
  897.              ctrl, i, addr); 
  898.         addr += 8;
  899.     }
  900. }
  901.  
  902.  
  903.  
  904. /**************************************************************************
  905.  *                      h 5 5 0 _ s e t 5 5 0                             *
  906.  **************************************************************************
  907.  *
  908.  *     Name:    h550_set550
  909.  *
  910.  *     Description:
  911.  *    
  912.  *        Initilize all ports on a given controller.
  913.  *
  914.  *     Returns:  Number of ports initialized.
  915.  *
  916.  **************************************************************************
  917. */
  918.  
  919. static int 
  920. h550_set550( int dev,
  921.          int ports )
  922. {
  923.     register int i;
  924.     caddr_t  addr;
  925.     int retval, h550_fcr;
  926.     uchar_t      iir;
  927.  
  928.     retval = 0;
  929.  
  930.     for (i = 0; i < ports; i++) {
  931.  
  932.     addr = einfo[dev].e_ports[i].port_addr;
  933.         OUTB(addr+FCR,0x01);                /* enable FIFOs */
  934.  
  935.     iir = INB(addr+IIR);
  936.         if ( (iir & 0xc0) == 0xc0 ) {
  937.  
  938.         switch ( TRIGGER ) {
  939.         case 4:
  940.             h550_fcr = 0x41;
  941.             break;
  942.         case 8:
  943.             h550_fcr = 0x81;
  944.             break;
  945.         case 14:
  946.             h550_fcr = 0xc1;
  947.             break;
  948.         default:
  949.             h550_fcr = 0x01;
  950.             break;
  951.         }
  952.  
  953.             OUTB(addr+FCR,h550_fcr);
  954.             ++retval;
  955.         }
  956.     }
  957.  
  958.     return(retval);
  959. }
  960.  
  961.  
  962.  
  963. /**************************************************************************
  964.  *                    h 5 5 0 _ e d t i n i t                             *
  965.  **************************************************************************
  966.  *
  967.  *     Name:      h550_edtinit
  968.  *
  969.  *     Description:
  970.  *
  971.  *        Called once for each Controller to initialize the 
  972.  *        controller. This initialization includes mapping
  973.  *        board's IO address space, setting up Interrupt number
  974.  *        and Interrup handler and initializing all the ports
  975.  *        addresses for the controller. 
  976.  *
  977.  *     Returns:
  978.  *
  979.  **************************************************************************
  980. */
  981. void
  982. h550edtinit( edt_t    *e )
  983. {
  984.     int iospace, eirq, ctlr_num;
  985.     edrvinfo_t *einf;
  986.     piomap_t *pmap;
  987.  
  988.     h550port_t *dp;
  989.     char *env;
  990.     register int ports, i;
  991.     caddr_t      addr;
  992.  
  993.  
  994.     /*
  995.      *    get the controller and the controller's port array
  996.       */
  997.     ctlr_num = e->e_ctlr;
  998.     einf = &einfo[ctlr_num];
  999.     dp   = &einf->e_ports[0];
  1000.  
  1001. #ifdef DEBUG2
  1002.     cmn_err(CE_DEBUG2,"Controller number is: %d\n", ctlr_num);
  1003. #endif /*DEBUG2 */
  1004.  
  1005.     /*
  1006.      *    Initialize all port variables for this controller.
  1007.      */
  1008.     for ( i = 0; i < MAX_PORTS; i++ ) {
  1009.         dp[i].dp_index  = i;
  1010.         dp[i].dp_ctl    = ctlr_num;
  1011.                 dp[i].port_addr = 0;
  1012.                 dp[i].xmitlev   = 16;           /* default */
  1013.                 dp[i].open      = 16;
  1014.                 dp[i].dp_state  = 0;
  1015.     }
  1016.  
  1017.     /*
  1018.      *  Map EISA address spaces for this controller
  1019.       *  (Note that there are 3 address: 1 for IO, 2 for Memory
  1020.      *   see EISA Driver requirements for more info).
  1021.      */
  1022.     for (iospace = 0; iospace < NBASE; iospace++) { 
  1023.         if (!e->e_space[iospace].ios_iopaddr)   /* no more addresses */
  1024.             continue;
  1025.     
  1026.         pmap = pio_mapalloc(e->e_bus_type, e->e_adap,
  1027.             &e->e_space[iospace], PIOMAP_FIXED, "h550");
  1028.  
  1029.         einf->e_addr[iospace] = pio_mapaddr(pmap,
  1030.             e->e_space[iospace].ios_iopaddr);
  1031.     }
  1032.  
  1033.     /* probe for device */
  1034.     if (badaddr(einf->e_addr[0], 1)) {
  1035.         cmn_err(CE_WARN, "h550: ctlr %d not installed",
  1036.             ctlr_num);
  1037.         return;
  1038.     }
  1039.  
  1040. #ifdef DEBUG2
  1041.     cmn_err(CE_NOTE,"Base address is: %x\n", einf->e_addr[0]);
  1042. #endif /* DEBUG2 */
  1043.  
  1044.     /*
  1045.      *    Allocate Interrupt Vector for this Controller.
  1046.      */
  1047.     eirq = eisa_ivec_alloc(e->e_adap, IRQ_MASK[ctlr_num],
  1048.                    EISA_EDGE_IRQ);
  1049.     if (eirq < 0) {
  1050.         cmn_err(CE_WARN, "h550: ctlr %d could not allocate IRQ", 
  1051.             ctlr_num);
  1052.         return;
  1053.     }
  1054.  
  1055.     einf->e_irq = eirq;
  1056.  
  1057.     /*
  1058.      *    Set the allocated Interrup Vector and assign proper
  1059.      *    Interrupt Handler to it (see EISA Driver requirement).
  1060.         */
  1061.     eisa_ivec_set(e->e_adap, eirq, intentrypnt[ctlr_num], ctlr_num);
  1062.  
  1063.     /*
  1064.      *    Get the actual number of working ports on this controller
  1065.      *    and calculate the base address of each Port's registers.
  1066.      */
  1067.     addr = einf->e_addr[0];
  1068.     if ( (ports = h550_getports(addr, MAX_PORTS) ) > 0) {
  1069.  
  1070.         h550_setaddr(addr, ports, ctlr_num);
  1071.  
  1072.         /*    set the Interrupt Mask (Register 7)  */
  1073.                if (h550_set550(ctlr_num, ports) == ports) {
  1074.                    einf->e_numports = ports;
  1075.  
  1076.                  for (i = 0; i < ports; i++)
  1077.                            einf->e_intmask = (einf->e_intmask << 1) + 1;
  1078.  
  1079.                    OUTB(addr+MASK,einf->e_intmask);  
  1080.  
  1081.             #ifdef DEBUG2
  1082.             cmn_err(CE_NOTE,"POLL register: 0x%x", INB(addr+POLL));
  1083.             #endif 
  1084.  
  1085.             if(showconfig)
  1086.                 cmn_err(CE_NOTE,
  1087.                    "HOSTESS 550 Controller found at %xH,"
  1088.                    "IRQ%d, %d ports", addr, eirq, ports );
  1089.         }
  1090.  
  1091.         /*
  1092.          *  h550_set550 did not return the number of ports expected
  1093.          *  so set all Port addresses to zero.         
  1094.            */
  1095.                else {
  1096.                    for (i=0;i<ports;i++)
  1097.                            dp[i].port_addr = 0;
  1098.             if(showconfig)
  1099.                 cmn_err(CE_NOTE,
  1100.                    "HOSTESS 550 Controller not found at %xH,"
  1101.                    "IRQ%d, %d ports", dp[0].port_addr,
  1102.                    eirq,ports);
  1103.                }
  1104.     }
  1105. }
  1106.  
  1107.  
  1108. /**************************************************************************
  1109.  *                       h 5 5 0 _ o p e n                                *
  1110.  **************************************************************************
  1111.  *
  1112.  *     Name:     h550_open
  1113.  *
  1114.  *     Description:
  1115.  *        Opens a UART port as a stream.
  1116.  *
  1117.  *     Returns:
  1118.  *
  1119.  **************************************************************************
  1120. */
  1121.  
  1122. static int
  1123. h550_open( queue_t    *rq,
  1124.        dev_t    *devp,
  1125.        int            flag,
  1126.        int        sflag,
  1127.        cred_t    *crp )
  1128. {
  1129.     h550port_t      *dp;
  1130.     minor_t         minor_no;
  1131.     minorNumInfo_t  mInfo;      
  1132.     short         port;
  1133.     short         ctl;
  1134.     int         s;
  1135.     int         error;
  1136.  
  1137.     chars_rcvd = 0;
  1138.     chars_xmt = 0;
  1139.  
  1140.     if (sflag)            /* only a simple stream driver */
  1141.         return(ENXIO);
  1142.  
  1143.     /*
  1144.      *    Get the Minor device number and figure out the 
  1145.       *    Controller Number.
  1146.      */
  1147.     minor_no = geteminor(*devp);
  1148.     getMinorInfo( minor_no, &mInfo);   
  1149.     ctl = mInfo.m_ctl;
  1150.  
  1151.     port = PORT(minor_no);
  1152.     if (port > MAX_PORTS)        /* fail if bad device # */
  1153.         return(ENXIO);
  1154.  
  1155.     dp = &einfo[ctl].e_ports[port];
  1156.  
  1157.     #ifdef DEBUG2
  1158.     cmn_err(CE_NOTE,"open: Ctl = %d, Port %d ", ctl, port);
  1159.     #endif /* DEBUG2 */
  1160.  
  1161.     s = LOCK_PORT(dp);
  1162.  
  1163.     if (!(dp->dp_state & (DP_ISOPEN | DP_WOPEN))) {    /* on the 1st open */
  1164.  
  1165.         ushort_t cflag;
  1166.         queue_t *wq = WR(rq);
  1167.         cflag = def_stty_ld.st_cflag;
  1168.  
  1169.         #ifdef DEBUG2
  1170.         cmn_err(CE_NOTE, "open: cflag = %x", cflag);
  1171.         #endif
  1172.  
  1173.         dp->dp_rsrv_duration = duart_rsrv_duration;
  1174.         dp->dp_state &= ~(DP_TXSTOP | DP_LIT | DP_BLOCK | DP_TX_TXON |
  1175.             DP_TX_TXOFF | DP_FLOW | DP_MODEM | DP_EXTCLK);
  1176.  
  1177.         if ( MODEM(minor_no) ) {
  1178.             #ifdef DEBUG2
  1179.             cmn_err(CE_NOTE,"open: This is a modem device %d\n",
  1180.                 minor_no);
  1181.             #endif
  1182.  
  1183.             dp->dp_state |= DP_MODEM;
  1184.             cflag &= ~CLOCAL;
  1185.         }
  1186.  
  1187.         if ( FLOW_MODEM(minor_no) ) {
  1188.             #ifdef DEBUG2
  1189.             cmn_err (CE_NOTE, "This is a Flow Ctl");
  1190.             #endif
  1191.             dp->dp_state |= DP_FLOW;
  1192.         }
  1193.  
  1194.         comtrol_h550_config(dp, cflag, &def_stty_ld.st_termio);
  1195.  
  1196.         dp->dp_state |= DP_WOPEN;
  1197.  
  1198.         if (!comtrol_h550_start_rx(dp)        /* wait for carrier */
  1199.             && !(dp->dp_cflag & CLOCAL)
  1200.             && !(flag & (FNONBLK | FNDELAY))) 
  1201.         {
  1202.             #ifdef DEBUG2
  1203.             cmn_err(CE_NOTE, "open: wait for DCD carrier");
  1204.             #endif
  1205.  
  1206.             do {
  1207.                 if (sleep((caddr_t)dp, STIPRI | PCATCH)) {
  1208.                     dp->dp_state &= ~(DP_WOPEN | DP_ISOPEN);
  1209.                     h550_zap(dp, HUPCL);
  1210.                     UNLOCK_PORT(dp,s);
  1211.                     return(EINTR);
  1212.                 }
  1213.             } while (!(dp->dp_state & DP_DCD));
  1214.         }
  1215.  
  1216.         /*
  1217.           *    Connect this port to stream
  1218.          */
  1219.         rq->q_ptr = (caddr_t)dp;
  1220.         wq->q_ptr = (caddr_t)dp;
  1221.         dp->dp_wq = wq;
  1222.         dp->dp_rq = rq;
  1223.         dp->dp_state |= DP_ISOPEN;
  1224.         dp->dp_state &= ~DP_WOPEN;
  1225.         dp->dp_cflag |= CREAD;
  1226.  
  1227.         h550_rclr(dp);            /* discard input */
  1228.  
  1229.         if (error = strdrv_push(rq, "stty_ld", devp, crp)) {
  1230.             dp->dp_state &= ~(DP_ISOPEN | DP_WOPEN);
  1231.             dp->dp_rq = NULL;
  1232.             dp->dp_wq = NULL;
  1233.             h550_zap(dp, HUPCL);
  1234.             UNLOCK_PORT(dp,s);
  1235.             return(error);
  1236.         }
  1237.     } 
  1238.     else {  /*  This port on this Controller is already opened !  */
  1239.         /*
  1240.           * you cannot open two streams to the same device. the dp
  1241.          * structure can only point to one of them. therefore, you
  1242.          * cannot open two different minor devices that are synonyms
  1243.          * for the same device. that is, you cannot open both ttym1
  1244.          * and ttyd1
  1245.           */
  1246.  
  1247.         if (dp->dp_rq != rq) {
  1248.  
  1249.             /* fail if already open */
  1250.             UNLOCK_PORT(dp,s);
  1251.             return(EBUSY);
  1252.         }
  1253.     }
  1254.  
  1255.     UNLOCK_PORT(dp,s);
  1256.     return(0);                /* return successfully */
  1257. }
  1258.  
  1259.  
  1260.  
  1261. /**************************************************************************
  1262.  *                    h 5 5 0 _ c l o s e                                 *
  1263.  **************************************************************************
  1264.  *
  1265.  *     Name:      h550_close
  1266.  *
  1267.  *     Description:
  1268.  *        Closes a port.
  1269.  *
  1270.  *     Returns:
  1271.  *
  1272.  **************************************************************************
  1273. */
  1274. static int
  1275. h550_close( queue_t    *rq,
  1276.         int        flag,
  1277.         cred_t    *crp )
  1278. {
  1279.     h550port_t  *dp;
  1280.     int        s;
  1281.  
  1282.     dp = (h550port_t *)rq->q_ptr;
  1283.     s = LOCK_PORT(dp);
  1284.  
  1285. #ifdef DEBUG2
  1286.     cmn_err(CE_NOTE,"close ctrl %d, port %d",
  1287.         dp->dp_ctl, dp->dp_index );
  1288. #endif /* DEBUG2 */
  1289.  
  1290.     if (dp->dp_state & DP_SE_PENDING) {
  1291.         dp->dp_state &= ~DP_SE_PENDING;
  1292.         str_unbcall(rq);
  1293.     }
  1294.  
  1295.     h550_flushr(dp);
  1296.     h550_flushw(dp);
  1297.  
  1298.     dp->dp_state &= ~(DP_ISOPEN | DP_WOPEN);
  1299.     dp->dp_rq = NULL;
  1300.     dp->dp_wq = NULL;
  1301.  
  1302.     h550_zap(dp, dp->dp_cflag & HUPCL);
  1303.  
  1304.     UNLOCK_PORT(dp,s);
  1305. }
  1306.  
  1307.  
  1308.  
  1309. /**************************************************************************
  1310.  *                     h 5 5 0 _ r s r v                                  *
  1311.  **************************************************************************
  1312.  *
  1313.  *     Name:      h550_rsrv
  1314.  *
  1315.  *     Description:
  1316.  *        Send one or more character up the stream.
  1317.  *
  1318.  *     Returns:
  1319.  *
  1320.  **************************************************************************
  1321. */
  1322. static void
  1323. h550_rsrv(queue_t *rq)
  1324. {
  1325.     mblk_t        *bp;
  1326.     h550port_t *dp;
  1327.     int        s;
  1328.  
  1329.     dp = (h550port_t *)rq->q_ptr;
  1330.     s = LOCK_PORT(dp);
  1331.  
  1332. #ifdef DEBUG2
  1333.     cmn_err(CE_NOTE,"Read service routine");
  1334. #endif /* DEBUG2 */
  1335.  
  1336.     
  1337. /*****  if (!canput(rq->q_next)) {   ****** against DDI/DKI  ******/
  1338.  
  1339.     if (!canputnext(rq) ) {         /* quit if upstream congested  */
  1340.         noenable(rq);
  1341.         UNLOCK_PORT(dp, s);
  1342.         return;
  1343.     }
  1344.  
  1345.     enableok(rq);
  1346.     if (dp->dp_state & DP_SE_PENDING) {
  1347.         dp->dp_state &= ~DP_SE_PENDING;
  1348.         str_unbcall(rq);
  1349.     }
  1350.  
  1351.     /* 
  1352.      * when we do not have an old buffer to send up, or when we are
  1353.      * timing things, send the current buffer
  1354.      */
  1355.     bp = dp->dp_rbp;
  1356.     if (bp && bp->b_wptr > bp->b_rptr
  1357.         && (!dp->dp_rmsg || !dp->dp_rsrv_cnt)) 
  1358.     {
  1359.         str_conmsg(&dp->dp_rmsg, &dp->dp_rmsge, bp);
  1360.         dp->dp_rmsg_len += (bp->b_wptr - bp->b_rptr);
  1361.         dp->dp_rbp = NULL;
  1362.     }
  1363.  
  1364.     bp = dp->dp_rmsg;
  1365.     if (bp) { 
  1366.         if (dp->dp_rmsg_len > dp->dp_rbsize)
  1367.             dp->dp_rbsize = dp->dp_rmsg_len;
  1368.         else
  1369.             dp->dp_rbsize = (dp->dp_rmsg_len + dp->dp_rbsize) / 2;
  1370.  
  1371.         dp->dp_rmsg_len = 0;
  1372.         dp->dp_rmsg = NULL;
  1373.  
  1374.         UNLOCK_PORT(dp, s);    /* without too much blocking, */
  1375.         putnext(rq, bp);    /* send the message */
  1376.         s = LOCK_PORT(dp);
  1377.     }
  1378.  
  1379.     comtrol_h550_iflow(dp, SEND_XON, !IGNORE_IXOFF);
  1380.  
  1381.     /* get a buffer now, rather than waiting for an interrupt */
  1382.     if (!dp->dp_rbp)
  1383.         (void)h550_getbp(dp, BPRI_LO);
  1384.  
  1385.     UNLOCK_PORT(dp, s);
  1386. }
  1387.  
  1388.  
  1389.  
  1390. /**************************************************************************
  1391.  *                         h 5 5 0 _ w p u t                              *
  1392.  **************************************************************************
  1393.  *
  1394.  *     Name:    h550_wput
  1395.  *
  1396.  *     Description:
  1397.  *        Start processing a message ('put' function).
  1398.  *
  1399.  *     Returns:
  1400.  *
  1401.  **************************************************************************
  1402. */
  1403. static int
  1404. h550_wput( queue_t    *wq, 
  1405.        mblk_t    *bp )
  1406. {
  1407.     h550port_t *dp;
  1408.     int        s;
  1409.     struct iocblk *iocp;
  1410.     unchar c;
  1411.  
  1412.     dp = (h550port_t *)wq->q_ptr;
  1413.     s = LOCK_PORT(dp);
  1414.  
  1415. #ifdef DEBUG2
  1416.     cmn_err(CE_NOTE,"Write put routine");
  1417. #endif /* DEBUG2 */
  1418.  
  1419.     /*   do according to Message type  */
  1420.     switch (bp->b_datap->db_type) {
  1421.  
  1422.     case M_FLUSH:    /* XXX may not want to restart output since flow
  1423.                control may be messed up */
  1424.         c = *bp->b_rptr;
  1425.         sdrv_flush(wq, bp);
  1426.  
  1427.         if (c & FLUSHW) {
  1428.             h550_flushw(dp);
  1429.             dp->dp_state &= ~DP_TXSTOP;
  1430.             comtrol_h550_start_tx(dp);    /* restart output */
  1431.         }
  1432.         if (c & FLUSHR)
  1433.             h550_flushr(dp);
  1434.         break;
  1435.  
  1436.     case M_DATA:
  1437.     case M_DELAY:
  1438.         h550_save(dp, wq, bp);
  1439.         break;
  1440.  
  1441.     case M_IOCTL:
  1442.         iocp = (struct iocblk *)bp->b_rptr;
  1443.  
  1444.         switch (iocp->ioc_cmd) {
  1445.  
  1446.         case TCXONC:
  1447.             switch (*(int *)(bp->b_cont->b_rptr)) {
  1448.             case 0:            /* stop output */
  1449.                 dp->dp_state |= DP_TXSTOP;
  1450.                 comtrol_h550_stop_tx(dp);
  1451.                 break;
  1452.             case 1:            /* resume output */
  1453.                 dp->dp_state &= ~DP_TXSTOP;
  1454.                 comtrol_h550_start_tx(dp);
  1455.                 break;
  1456.             case 2:
  1457.                 comtrol_h550_iflow(dp, SEND_XOFF, IGNORE_IXOFF);
  1458.                 break;
  1459.             case 3:
  1460.                 comtrol_h550_iflow(dp, SEND_XON, IGNORE_IXOFF);
  1461.                 break;
  1462.             default:
  1463.                 iocp->ioc_error = EINVAL;
  1464.                 break;
  1465.             }
  1466.  
  1467.             iocp->ioc_count = 0;
  1468.             bp->b_datap->db_type = M_IOCACK;
  1469.             qreply(wq, bp);
  1470.             break;
  1471.  
  1472.         case TCGETA: /* XXXrs - Don't wait until output? */
  1473.             ASSERT(iocp->ioc_count == sizeof(struct termio));
  1474.             h550_tcgeta(dp->dp_wq,bp, &dp->dp_termio);
  1475.             break;
  1476.  
  1477.         case TCSETA: /* XXXrs - Don't wait until output? */
  1478.             ASSERT(iocp->ioc_count == sizeof(struct termio));
  1479.             (void)h550_tcset(dp,bp);
  1480.             qreply(wq,bp);
  1481.             break;
  1482.  
  1483.         case TCSBRK:    /* send BREAK */
  1484.         case TCSETAF:    /* drain output, flush input, set parameters */
  1485.         case TCSETAW:    /* drain output, set paramaters */
  1486.             h550_save(dp, wq, bp);
  1487.             break;
  1488.  
  1489.         case TCBLKMD:
  1490.             dp->dp_iflag |= IBLKMD;
  1491.             iocp->ioc_count = 0;
  1492.             bp->b_datap->db_type = M_IOCACK;
  1493.             qreply(wq, bp);
  1494.             break;
  1495.  
  1496.         default:
  1497.             bp->b_datap->db_type = M_IOCNAK;
  1498.             qreply(wq, bp);
  1499.             break;
  1500.         }
  1501.         break;
  1502.  
  1503.     default:
  1504.         sdrv_error(wq, bp);
  1505.     }
  1506.  
  1507.     UNLOCK_PORT(dp, s);
  1508. }
  1509.  
  1510. /**************************************************************************
  1511.  *                         h 5 5 0 _ h a n d l e _ i n t r                *
  1512.  **************************************************************************
  1513.  *
  1514.  *     Name:      h550_handle_intr
  1515.  *
  1516.  *     Description:
  1517.  *        Handle interrupt for a given port on a given Controller.
  1518.  *
  1519.  *     Returns:   0 if nothing to do on the specified Ctlr,
  1520.  *          1 if something was done
  1521.  *
  1522.  **************************************************************************
  1523. */
  1524.  
  1525. static int
  1526. h550_handle_intr ( int   ctl,
  1527.            int   port )
  1528. {
  1529.     h550port_t      *dp;
  1530.     volatile caddr_t addr;
  1531.     uchar_t       iir_val, ier_val;
  1532.     uchar_t              msr_val, lsr_val;
  1533.     int             i, s;
  1534.  
  1535.     dp = &einfo[ctl].e_ports[port];
  1536.     addr = dp->port_addr;
  1537.  
  1538.     s = LOCK_PORT(dp); 
  1539.  
  1540.     iir_val = INB(addr+IIR);
  1541.  
  1542.     #ifdef DEBUG2
  1543.     cmn_err(CE_NOTE,"intr: Interrupt, Ctl = %d, Port = %d, IIR = %x",
  1544.         ctl, port, iir_val);
  1545.     #endif /* DEBUG2 */
  1546.  
  1547.     if (iir_val & INTR_PEND) {
  1548.         UNLOCK_PORT(dp, s);
  1549.         return(0);
  1550.     }
  1551.  
  1552.     switch(iir_val & 0x0e) {
  1553.  
  1554.         /* receive character/error interrupt */
  1555.         case RDATA_AVAIL:
  1556.         case RLINE_STAT:         
  1557.  
  1558.             #ifdef DEBUG2
  1559.             cmn_err(CE_NOTE, "intr: RDATA_AVAIL or RLINE_STAT");
  1560.             #endif
  1561.  
  1562.             SYSINFO.rcvint++;
  1563.             h550_rx(dp);
  1564.             break;
  1565.  
  1566.         /* modem status interrupt */
  1567.         case MODEM_STAT:                 
  1568.  
  1569.  
  1570.             /* handle CTS interrupt only if we care, - only if 
  1571.              * CTS has changed and modem interrupts are enabled 
  1572.               *
  1573.               * If the port's state shows that CTS is active but 
  1574.              * the MSR doesn't, reset the port's CTS state 
  1575.               *
  1576.               * If the port doesn't show active CTS, but the MSR 
  1577.              * does, set the port's CTS state to active and 
  1578.              * restart transmit
  1579.               */
  1580.             ier_val = INB(addr+IER);
  1581.             msr_val = INB(addr+MSR);
  1582.             
  1583.             #ifdef DEBUG2
  1584.             cmn_err(CE_NOTE, 
  1585.                 "intr: Modem_Stat , IER = %x, MSR = %x",
  1586.                 ier_val, msr_val);
  1587.             #endif
  1588.  
  1589.             if ( (msr_val & DCTS) && (ier_val & EDSSI) ) {
  1590.                 if ( (dp->dp_state & DP_CTS) &&
  1591.                     !(msr_val & CTS) ) {
  1592.  
  1593.                     #ifdef DEBUG2
  1594.                     cmn_err(CE_NOTE, 
  1595.                         "intr: Modem CTS, case 1");
  1596.                     #endif
  1597.  
  1598.                     SYSINFO.mdmint++;
  1599.                     dp->dp_state &= ~DP_CTS;
  1600.                 } 
  1601.                 else if ( !(dp->dp_state & DP_CTS) &&
  1602.                           (msr_val & CTS) ) {
  1603.  
  1604.                                         #ifdef DEBUG2
  1605.                                         cmn_err(CE_NOTE, 
  1606.                         "intr: Modem CTS, case 2");
  1607.                                         #endif
  1608.  
  1609.                     SYSINFO.mdmint++;
  1610.                     dp->dp_state |= DP_CTS;
  1611.                     comtrol_h550_start_tx(dp);
  1612.                 }
  1613.             }
  1614.  
  1615.             /* handle DCD interrupt only if we care - only if
  1616.              * DCD has changed and the modem interrupts are 
  1617.              * enabled
  1618.               *
  1619.               * If the port's state shows that DCD is active 
  1620.              * but the MSR doesn't, reset the port's DCD state 
  1621.              * and kill the port's process
  1622.               *
  1623.               * If the port's state shows DCD inactive, but the 
  1624.              * MSR does, set the port's DCD state to active 
  1625.              * and process the stream waiting for the carrier
  1626.               */
  1627.             if ( (msr_val & DDCD) && (ier_val & EDSSI) ) {
  1628.                 if ( (dp->dp_state & DP_DCD) &&
  1629.                         !(msr_val & DCD) ) {
  1630.  
  1631.                                         #ifdef DEBUG2
  1632.                                         cmn_err(CE_NOTE, 
  1633.                                                 "intr: Modem DCD, case 1");
  1634.                                         #endif
  1635.  
  1636.                     SYSINFO.mdmint++;
  1637.                     dp->dp_state &= ~DP_DCD;
  1638.                     h550_coff(dp);
  1639.                 } 
  1640.                 else if ( !(dp->dp_state & DP_DCD) &&
  1641.                           (msr_val & DCD) ) {
  1642.  
  1643.                                         #ifdef DEBUG2
  1644.                                         cmn_err(CE_NOTE, 
  1645.                                                 "intr: Modem DCD, case 2");
  1646.                                         #endif
  1647.  
  1648.                     SYSINFO.mdmint++;
  1649.                     dp->dp_state |= DP_DCD;
  1650.                         h550_con(dp);
  1651.                 }
  1652.             }
  1653.  
  1654.             /* handle BREAK interrupt */
  1655.             lsr_val = INB(addr+LSR);
  1656.  
  1657.             #ifdef DEBUG2
  1658.             cmn_err(CE_NOTE, "intr: Modem_Stat, LSR = %x", lsr_val);
  1659.             #endif
  1660.  
  1661.             if (lsr_val & BI) {
  1662.                 #ifdef DEBUG2
  1663.                 cmn_err(CE_NOTE, "intr: Modem_Stat, BREAK_ON");
  1664.                 #endif
  1665.                 dp->dp_state |= DP_BREAK_ON;
  1666.             }
  1667.             else  {
  1668.                                 #ifdef DEBUG2
  1669.                                 cmn_err(CE_NOTE, "intr: Modem_Stat, BREAK_OFF");
  1670.                                 #endif
  1671.  
  1672.                 dp->dp_state &= ~DP_BREAK_ON;
  1673.             }
  1674.             break;
  1675.  
  1676.         /* transmit buffer empty interrupt */
  1677.         case THREI:             
  1678.             #ifdef DEBUG2
  1679.             cmn_err(CE_NOTE, "intr: THREI (Transmt buf empty)");
  1680.             #endif
  1681.             SYSINFO.xmtint++;
  1682.             h550_tx(dp,0);
  1683.             break;
  1684.  
  1685.         default:
  1686.             cmn_err(CE_WARN,"intr: Unknown interrupt type");
  1687.             return(0);
  1688.     }
  1689.  
  1690.     UNLOCK_PORT(dp, s);
  1691.     return(1);
  1692.  
  1693. }
  1694.  
  1695.  
  1696.  
  1697. /**************************************************************************
  1698.  *                       h 5 5 0 _ p o l l                                *
  1699.  **************************************************************************
  1700.  *
  1701.  *     Name:       h550_poll
  1702.  *
  1703.  *     Description:
  1704.  *        Our interrupt handler. It checks the given Controller
  1705.  *        number and sees if it is the one needs servicing.
  1706.  *
  1707.  *     Returns:
  1708.  *
  1709.  **************************************************************************
  1710. */
  1711. static void
  1712. h550_poll( int   ctlr )
  1713. {
  1714.     int i;
  1715.     edrvinfo_t       *einf;
  1716.     volatile caddr_t addr;
  1717.     uchar_t         b;
  1718.  
  1719.     /*   access this controller's data area   */
  1720.         einf = &einfo[ctlr];
  1721.     addr = einf->e_addr[0];
  1722.  
  1723.     #ifdef DEBUG2
  1724.     cmn_err(CE_NOTE,"poll: Interrupt received, Ctl = %x", ctlr);
  1725.     #endif /* DEBUG2 */
  1726.  
  1727.     /*
  1728.      * Look at POLL register and service only those ports with 
  1729.      * pending interrupts 
  1730.      */
  1731.     b = INB(addr+POLL);
  1732.  
  1733.     while ( b ) {
  1734.  
  1735.         #ifdef DEBUG2
  1736.         cmn_err(CE_NOTE, "poll: Poll value = %x", b);
  1737.         #endif
  1738.  
  1739.         for (i = 0; i < MAX_PORTS; i++)
  1740.             if ( b & (1 << i)) {
  1741.                  #ifdef DEBUG2
  1742.                 cmn_err(CE_NOTE, "poll: port %d interrupted",
  1743.                       i);
  1744.                 #endif
  1745.                 h550_handle_intr(ctlr, i);
  1746.             }
  1747.         b = INB(addr+POLL);
  1748.     }
  1749. }
  1750.  
  1751.  
  1752.  
  1753. /**************************************************************************
  1754.  *                         h 5 5 0 _ g e t b p                            *
  1755.  **************************************************************************
  1756.  *
  1757.  *     Name:      h550_getbp
  1758.  *
  1759.  *     Description:
  1760.  *        Get a new buffer. This routine should only be called 
  1761.  *        when it is safe from an interrupt.
  1762.  *
  1763.  *     Returns:  NULL or the new buffer
  1764.  *
  1765.  **************************************************************************
  1766. */
  1767.  
  1768. static mblk_t*
  1769. h550_getbp( h550port_t    *dp,
  1770.         uint_t    pri )
  1771. {
  1772.     mblk_t *bp;
  1773.     mblk_t *rbp;
  1774.     int size;
  1775.     int size0;
  1776.     volatile caddr_t addr = dp->port_addr;
  1777.  
  1778. #ifdef DEBUG2
  1779.     cmn_err(CE_NOTE,"Get new buffer routine");
  1780. #endif /* DEBUG2 */
  1781.  
  1782.     rbp = dp->dp_rbp;
  1783.  
  1784.     /*
  1785.      *      if overflowing or current buffer empty, do not 
  1786.      *    need another buffer.
  1787.      */
  1788.     if ( ( dp->dp_rmsg_len >= MAX_RMSG_LEN ) ||
  1789.          ( rbp && rbp->b_rptr >= rbp->b_wptr ) ) {
  1790.         cmn_err(CE_NOTE,"don't need another");
  1791.         bp = NULL;
  1792.     } 
  1793.     else {
  1794.         /*
  1795.          *    get another buffer, but always keep room to grow.
  1796.          *    this helps prevent deadlock
  1797.           */
  1798.         size0 = (dp->dp_rbsize += dp->dp_rbsize / 4);
  1799.         if (size0 > MAX_RBUF_LEN)
  1800.             size0 = dp->dp_rbsize = MAX_RBUF_LEN;
  1801.         else if (size0 < MIN_RMSG_LEN)
  1802.             size0 = MIN_RMSG_LEN;
  1803.         size = size0;
  1804.  
  1805.         for ( ; ; ) {
  1806.  
  1807.             bp = allocb(size, pri);
  1808.  
  1809.             if (bp)
  1810.                 break;
  1811.             if (pri == BPRI_HI && (size >>= 2) >= MIN_RMSG_LEN)
  1812.                 continue;
  1813.  
  1814.             if ( !(dp->dp_state & DP_SE_PENDING) ) {
  1815.                 bp = str_allocb(size0, dp->dp_rq, BPRI_HI);
  1816.                 if (!bp)
  1817.                     dp->dp_state |= DP_SE_PENDING;
  1818.             }
  1819.             break;
  1820.         }
  1821.     }
  1822.  
  1823.     if ( !rbp ) {
  1824.         dp->dp_rbp = bp;
  1825.     }
  1826.     else if ( (bp) || (rbp->b_wptr >= rbp->b_datap->db_lim) ) {
  1827.  
  1828.         /*
  1829.          * we have an old buffer and a new buffer, or old buffer is
  1830.          * full 
  1831.          */
  1832.         str_conmsg(&dp->dp_rmsg, &dp->dp_rmsge, rbp);
  1833.         dp->dp_rmsg_len += (rbp->b_wptr - rbp->b_rptr);
  1834.         dp->dp_rbp = bp;
  1835.     }
  1836.  
  1837.     if ( (dp->dp_rmsg_len >= XOFF_RMSG_LEN) || (!dp->dp_rbp) ) {
  1838.         comtrol_h550_iflow ( dp, SEND_XOFF, !IGNORE_IXOFF );
  1839.  
  1840.     }
  1841.  
  1842.     return(bp);
  1843. }
  1844.  
  1845.  
  1846. /**************************************************************************
  1847.  *                        h 5 5 0 _ s l o w r                             *
  1848.  **************************************************************************
  1849.  *
  1850.  *     Name:    h550_slowr
  1851.  *
  1852.  *     Description:
  1853.  *        This routine puts characters in upstream queue. 
  1854.  *        The routine is slow and should be called infrequently.
  1855.  *
  1856.  *     Returns:
  1857.  *
  1858.  **************************************************************************
  1859. */
  1860.  
  1861. static void
  1862. h550_slowr( h550port_t    *dp,
  1863.         uchar_t     c )
  1864. {
  1865.     mblk_t *bp;
  1866.  
  1867. #ifdef DEBUG2
  1868.     cmn_err(CE_NOTE,"Slow read routine");
  1869. #endif /* DEBUG2 */
  1870.  
  1871.     if (dp->dp_iflag & IBLKMD)    /* this kludge apes the old */
  1872.         return;            /* block mode hack */
  1873.  
  1874.     /*   get a buffer if we have none  */
  1875.     if ( !(bp = dp->dp_rbp) &&
  1876.          !(bp = h550_getbp(dp, BPRI_HI)) ) {
  1877.  
  1878.         dp->dp_allocb_fail++;
  1879.         return;
  1880.     }
  1881.  
  1882.     /*
  1883.      *   Put the character into the buffer and 
  1884.      *   send the buffer if it is full
  1885.      */
  1886.     *bp->b_wptr = c;
  1887.     if (++bp->b_wptr >= bp->b_datap->db_lim) {
  1888.         (void)h550_getbp(dp, BPRI_LO);    /* send buffer when full */
  1889.     }
  1890. }
  1891.  
  1892.  
  1893.  
  1894. /**************************************************************************
  1895.  *                         h 5 5 0 _ r x                                  *
  1896.  **************************************************************************
  1897.  *
  1898.  *     Name:    h550_rx
  1899.  *
  1900.  *     Description:
  1901.  *        Interrupt handler for input character/error.
  1902.  *
  1903.  *     Returns:
  1904.  *
  1905.  **************************************************************************
  1906. */
  1907. static void
  1908. h550_rx( h550port_t  *dp )
  1909. {
  1910.     int c;
  1911.     uchar_t sr;
  1912.     mblk_t *bp;
  1913.     volatile caddr_t addr;
  1914.  
  1915.     addr = dp->port_addr;
  1916.  
  1917. #ifdef DEBUG2
  1918.     cmn_err(CE_NOTE,"rx: Read routine, dp->dp_state = %x", dp->dp_state);
  1919. #endif /* DEBUG2 */
  1920.  
  1921.     /* must be open to input */
  1922.     if ( (dp->dp_state & (DP_ISOPEN | DP_WOPEN)) != DP_ISOPEN ) {
  1923.         if ( !(dp->dp_state & (DP_ISOPEN | DP_WOPEN)) )
  1924.             h550_zap(dp, dp->dp_cflag & HUPCL);
  1925.         else
  1926.             h550_rclr(dp);    /* just forget it if partly open */
  1927.         return;
  1928.     }
  1929.  
  1930.     /*
  1931.      *   Must be reading, to read.  DCD must be on for modem 
  1932.      *  port to read
  1933.      */ 
  1934.     if ( !(dp->dp_cflag & CREAD) ) {
  1935.  
  1936.         #ifdef DEBUG2
  1937.         cmn_err(CE_NOTE, "rx: not in READ mode, dp_cflag = %x",
  1938.             dp->dp_cflag);
  1939.         #endif
  1940.  
  1941.         h550_rclr(dp);
  1942.         return;
  1943.     }
  1944.  
  1945.     /* process all available characters */
  1946.     while ( (c = comtrol_h550_getchar(dp) ) != -1 ) {
  1947.  
  1948.         SYSINFO.rawch++;
  1949.         chars_rcvd++;
  1950.  
  1951.         sr = c >> 8;
  1952.         c &= 0xff;
  1953.  
  1954.         #ifdef DEBUG
  1955.         cmn_err(CE_NOTE, "rx: LSR = %x, Received Char: %x [%c]", sr,
  1956.             c, (c =='\n' || c == '\r')? '.':c);
  1957.         #endif
  1958.  
  1959.         /* if we get a control-A, debug on this port */
  1960.         if ( (kdebug) && (c == CNTRL_A) ) {
  1961.             debug("ring");
  1962.             continue;
  1963.         }
  1964.  
  1965.         /*
  1966.           *     XON and XOFF
  1967.          *     Start/Stop output (if permitted)
  1968.          */ 
  1969.         if ( dp->dp_iflag & IXON ) {
  1970.  
  1971.             uchar_t cs = c;
  1972.  
  1973.             if (dp->dp_iflag & ISTRIP)
  1974.                 cs &= 0x7f;
  1975.  
  1976.             if (dp->dp_state & DP_TXSTOP
  1977.                 && (cs == dp->dp_cc[VSTART]
  1978.                 || (dp->dp_iflag & IXANY
  1979.                 && (cs != dp->dp_cc[VSTOP]
  1980.                 || dp->dp_line == LDISC0)))) {
  1981.              
  1982.                 dp->dp_state &= ~DP_TXSTOP;
  1983.                 comtrol_h550_start_tx(dp); /* restart output */
  1984.  
  1985.                 if (cs == dp->dp_cc[VSTART])
  1986.                     continue;
  1987.             } 
  1988.  
  1989.             else if (DP_LIT & dp->dp_state) {
  1990.                 dp->dp_state &= ~DP_LIT;
  1991.             } 
  1992.  
  1993.             else if (cs == dp->dp_cc[VSTOP]) {
  1994.              
  1995.                 dp->dp_state |= DP_TXSTOP;
  1996.                 comtrol_h550_stop_tx(dp);    /* stop output */
  1997.                 continue;
  1998.             } 
  1999.  
  2000.             else if (cs == dp->dp_cc[VSTART]) {
  2001.                 continue;     /* ignore extra control-Qs */
  2002.             } 
  2003.  
  2004.             else if (cs == dp->dp_cc[VLNEXT]
  2005.                 && dp->dp_line != LDISC0) {
  2006.                 dp->dp_state |= DP_LIT;    /* just note escape */
  2007.             }
  2008.         }
  2009.  
  2010.         /*
  2011.          *   we got a Break Interrupt
  2012.          */
  2013.         if (sr & BI) { 
  2014.          
  2015.             if (dp->dp_iflag & IGNBRK)
  2016.                 continue;             /* ignore it if ok */
  2017.  
  2018.             if (dp->dp_iflag & BRKINT) {
  2019.              
  2020.                 h550_flushr(dp);
  2021.                 (void)putctl1(dp->dp_rq->q_next,
  2022.                     M_FLUSH, FLUSHRW);
  2023.                 (void)putctl1(dp->dp_rq->q_next,
  2024.                     M_PCSIG, SIGINT);
  2025.                 continue;
  2026.             }
  2027.  
  2028.             if (dp->dp_iflag & PARMRK) {
  2029.              
  2030.                 h550_slowr(dp, '\377');
  2031.                 h550_slowr(dp, '\000');
  2032.             }
  2033.  
  2034.             c = '\000';
  2035.         }
  2036.  
  2037.          else if ( sr & (FE | OE | PE) ) {
  2038.          
  2039.             if (sr & OE) {
  2040.                 dp->dp_over++;    /* count overrun */
  2041.                 INB(addr+LSR);
  2042.             }
  2043.  
  2044.             if (dp->dp_iflag & IGNPAR) {
  2045.                 continue;
  2046.             } 
  2047.  
  2048.             else if ( !(dp->dp_iflag & INPCK) ) {
  2049.                 /* ignore input parity errors if asked */
  2050.             } 
  2051.  
  2052.             else if ( sr & (PE | FE) ) {
  2053.              
  2054.                 if (sr & FE)
  2055.                     dp->dp_fe++;
  2056.  
  2057.                 if (dp->dp_iflag & PARMRK) {
  2058.                     h550_slowr(dp, '\377');
  2059.                     h550_slowr(dp, '\000');
  2060.                 } 
  2061.                 else {
  2062.                     c = '\000';
  2063.                 }
  2064.             }
  2065.  
  2066.  
  2067.         } 
  2068.  
  2069.         else if (dp->dp_iflag & ISTRIP) { 
  2070.             c &= 0x7f;
  2071.         } 
  2072.  
  2073.         else if (c == '\377' && dp->dp_iflag & PARMRK) {
  2074.             h550_slowr(dp, '\377');
  2075.         }
  2076.  
  2077.         if (!(bp = dp->dp_rbp)    /* get a buffer if we have none */
  2078.             && !(bp = h550_getbp(dp, BPRI_HI))) {
  2079.             dp->dp_allocb_fail++;
  2080.             continue;    /* forget it no buffer available */
  2081.         }
  2082.  
  2083.         *bp->b_wptr = c;
  2084.  
  2085.         if (++bp->b_wptr >= bp->b_datap->db_lim) {
  2086.             (void)h550_getbp(dp, BPRI_LO);    /* send when full */
  2087.         }
  2088.     }
  2089.  
  2090.  
  2091.     if (!dp->dp_rsrv_cnt && dp->dp_rbp) {
  2092.  
  2093.         if (dp->dp_rsrv_duration <= 0
  2094.             || dp->dp_rsrv_duration > HZ / 10) {
  2095.          
  2096.             if (dp->dp_state & DP_ISOPEN && canenable(dp->dp_rq))
  2097.                 qenable(dp->dp_rq);
  2098.         } 
  2099.  
  2100.         else {
  2101.             (void)STREAMS_TIMEOUT(h550_rsrv_timer,
  2102.                 (caddr_t)dp, dp->dp_rsrv_duration);
  2103.             dp->dp_rsrv_cnt = MAX_RSRV_CNT;
  2104.         }
  2105.     }
  2106. }
  2107.  
  2108.  
  2109. /**************************************************************************
  2110.  *                         h 5 5 0 _ c o n                                *
  2111.  **************************************************************************
  2112.  *
  2113.  *     Name:    h550_con
  2114.  *
  2115.  *     Description:
  2116.  *        Process Carrier_On Interrupt for a given port.
  2117.  *
  2118.  *     Returns:
  2119.  *
  2120.  **************************************************************************
  2121. */
  2122.  
  2123. static void
  2124. h550_con( h550port_t  *dp )
  2125. {
  2126. #ifdef DEBUG2
  2127.     cmn_err(CE_NOTE,"Carrier ON routine");
  2128. #endif /* DEBUG2 */
  2129.  
  2130.     if (dp->dp_state & DP_WOPEN)
  2131.         wakeup((caddr_t)dp);    /* awaken open() requests */
  2132. }
  2133.  
  2134.  
  2135.  
  2136. /**************************************************************************
  2137.  *                         h 5 5 0 _ c o f f                              *
  2138.  **************************************************************************
  2139.  *
  2140.  *     Name:    h550_coff
  2141.  *
  2142.  *     Description:
  2143.  *        Process Carrier_Off Interrupt for a given port.
  2144.  *
  2145.  *     Returns:
  2146.  *
  2147.  **************************************************************************
  2148. */
  2149. static void
  2150. h550_coff( h550port_t  *dp )
  2151. {
  2152.  
  2153. #ifdef DEBUG2
  2154.     cmn_err(CE_NOTE,"Carrier OFF routine");
  2155. #endif /* DEBUG2 */
  2156.  
  2157.     if ( !(dp->dp_cflag & CLOCAL) && /* worry only for an open modem */
  2158.           (dp->dp_state & DP_ISOPEN) ) {
  2159.      
  2160.         h550_zap(dp, HUPCL);    /* kill the modem */
  2161.         flushq(dp->dp_wq, FLUSHDATA);
  2162.         (void)putctl1(dp->dp_rq->q_next, M_FLUSH, FLUSHW);
  2163.         (void)putctl(dp->dp_rq->q_next, M_HANGUP);
  2164.     }
  2165. }
  2166.  
  2167.  
  2168. /**************************************************************************
  2169.  *                         h 5 5 0 _ t x                                  *
  2170.  **************************************************************************
  2171.  *
  2172.  *     Name:    h550_tx
  2173.  *
  2174.  *     Description:
  2175.  *        Outputs to a port.
  2176.  *
  2177.  *     Returns:
  2178.  *
  2179.  **************************************************************************
  2180. */
  2181.  
  2182. static void
  2183. h550_tx( h550port_t *dp, 
  2184.      int        prime )
  2185. {
  2186.     uchar_t c;
  2187.     mblk_t *wbp;
  2188.     int local_fifo_size, count;
  2189.     volatile caddr_t addr;
  2190.  
  2191.     addr = dp->port_addr;
  2192.  
  2193.     #ifdef DEBUG2
  2194.     cmn_err(CE_NOTE,"tx: Output routine");
  2195.     #endif /* DEBUG2 */
  2196.  
  2197.     if (!comtrol_h550_txrdy(dp))
  2198.         return;
  2199.     
  2200.     local_fifo_size = count = 1;
  2201.  
  2202.     /* send all we can */
  2203.     while ( comtrol_h550_txrdy(dp) ) {
  2204.  
  2205.         if (!(dp->dp_state & DP_ISOPEN)
  2206.             || dp->dp_state & (DP_BREAK | DP_BREAK_QUIET)
  2207.             || dp->dp_state & (DP_TXSTOP | DP_TIMEOUT)
  2208.             && !(dp->dp_state & (DP_TX_TXON | DP_TX_TXOFF))) {
  2209.          
  2210.             comtrol_h550_stop_tx(dp);
  2211.             return;
  2212.         }
  2213.  
  2214.         SYSINFO.outch++;
  2215.  
  2216.         /*   send XON or XOFF     */
  2217.         if (dp->dp_state & DP_TX_TXON) {
  2218.          
  2219.             if ( (dp->dp_state & DP_FLOW) &&
  2220.                 !(dp->dp_state & DP_CTS) ) {
  2221.              
  2222.                 comtrol_h550_stop_tx(dp);
  2223.                 return;
  2224.             }
  2225.  
  2226.             c = dp->dp_cc[VSTART];
  2227.             dp->dp_state &= ~(DP_TX_TXON | DP_TX_TXOFF | DP_BLOCK);
  2228.         } 
  2229.  
  2230.         else if (dp->dp_state & DP_TX_TXOFF) {
  2231.  
  2232.             if ( (dp->dp_state & DP_FLOW) &&
  2233.                  !(dp->dp_state & DP_CTS) ) {
  2234.              
  2235.                 comtrol_h550_stop_tx(dp);
  2236.                 return;
  2237.             }
  2238.  
  2239.             c = dp->dp_cc[VSTOP];
  2240.             dp->dp_state &= ~DP_TX_TXOFF;
  2241.             dp->dp_state |= DP_BLOCK;
  2242.  
  2243.         } 
  2244.  
  2245.         else {
  2246.             if (!(wbp = dp->dp_wbp)) {    /* get another msg */
  2247.                 wbp = getq(dp->dp_wq);
  2248.                 if (!wbp) {
  2249.                     comtrol_h550_stop_tx(dp);
  2250.                     return;
  2251.                 }
  2252.  
  2253.                 switch (wbp->b_datap->db_type) {
  2254.  
  2255.                 case M_DATA:
  2256.                     dp->dp_wbp = wbp;
  2257.                     break;
  2258.  
  2259.                 /* must wait until output drained */
  2260.                 case M_DELAY:    /* start output delay */
  2261.  
  2262.                     if (count == local_fifo_size) {
  2263.                         dp->dp_state |= DP_TIMEOUT;
  2264.                         dp->dp_tid = 
  2265.                            STREAMS_TIMEOUT(h550_delay,
  2266.                                (caddr_t)dp,
  2267.                            *(int *)wbp->b_rptr);
  2268.                         freemsg(wbp);
  2269.                         continue;
  2270.                     }     
  2271.                     else {
  2272.                         putbq(dp->dp_wq, wbp);
  2273.                         return;
  2274.                     }
  2275.  
  2276.                 /* must wait until output drained */
  2277.                 case M_IOCTL:
  2278.                     if (count == local_fifo_size) {
  2279.                         h550_i_ioctl(dp, wbp);
  2280.                         continue;
  2281.                     } 
  2282.                     else {
  2283.                         putbq(dp->dp_wq, wbp);
  2284.                         return;
  2285.                     }
  2286.  
  2287.                 default:
  2288.                     panic("bad uart msg");
  2289.                 }
  2290.             }
  2291.  
  2292.             if ( (dp->dp_state & DP_FLOW) &&
  2293.                 !(dp->dp_state & DP_CTS) ) {
  2294.                 comtrol_h550_stop_tx(dp);
  2295.                 return;
  2296.             }
  2297.  
  2298.             if (wbp->b_rptr >= wbp->b_wptr) {
  2299.                 dp->dp_wbp = rmvb(wbp, wbp);
  2300.                 freeb(wbp);
  2301.                 continue;
  2302.             }
  2303.  
  2304.             c = *wbp->b_rptr++;
  2305.         }
  2306.  
  2307.         #ifdef DEBUG
  2308.         cmn_err(CE_NOTE, "tx: Sending char: %x [%c]", c,
  2309.         (c =='\n' || c == '\r')? '.':c);
  2310.         #endif
  2311.  
  2312.         comtrol_h550_putchar(dp, c);
  2313.         chars_xmt++;
  2314.         count--;
  2315.     }
  2316.  
  2317.     /*
  2318.      * If the queue is now empty, put an empty data block on it
  2319.      * to prevent a close from finishing prematurely.
  2320.      */
  2321.     if ( (!dp->dp_wq->q_first) && 
  2322.          (dp->dp_wbp)          && 
  2323.          (wbp = allocb(0, BPRI_HI)) ) {
  2324.         putbq(dp->dp_wq, wbp);
  2325.      }
  2326.  
  2327. }
  2328.  
  2329. /**************************************************************************
  2330.  *                 c o m t r o l _ h 5 5 0 _ t x r d y                       *
  2331.  **************************************************************************
  2332.  *
  2333.  *     Name:    comtrol_h550_txrdy
  2334.  *
  2335.  *     Description:
  2336.  *        Determine if a given port is ready to transmit a 
  2337.  *        character or not.
  2338.  *
  2339.  *     Returns: 0 = Not Ready
  2340.  *
  2341.  **************************************************************************
  2342. */
  2343.  
  2344. static int
  2345. comtrol_h550_txrdy( h550port_t  *dp )
  2346. {
  2347.     volatile caddr_t addr;
  2348.     uchar_t        b;
  2349.     addr = dp->port_addr;
  2350.  
  2351.  
  2352.     b = INB(addr+LSR);
  2353.  
  2354.     #ifdef DEBUG2
  2355.     cmn_err(CE_NOTE,"txrdy: Tx Ready routine, LSR = %x, LSR & THRE = %x",
  2356.         b, b & THRE );
  2357.     #endif /* DEBUG2 */
  2358.  
  2359.     return( b & THRE);
  2360. }
  2361.  
  2362.  
  2363. /**************************************************************************
  2364.  *                c o m t r o l _ h 5 5 0 _ p u t c h a r                 *
  2365.  **************************************************************************
  2366.  *
  2367.  *     Name:    comtrol_h550_putchar
  2368.  *
  2369.  *     Description:
  2370.  *        Transmit a character. The routine 'comtrol_h550_txrdy'
  2371.  *        must be called first to make sure the port is ready.
  2372.  *
  2373.  *     Returns:
  2374.  *
  2375.  **************************************************************************
  2376. */
  2377.  
  2378. static void
  2379. comtrol_h550_putchar(h550port_t *dp, uchar_t c)
  2380. {
  2381.     volatile caddr_t addr;
  2382.  
  2383.     addr = dp->port_addr;
  2384.  
  2385.     #ifdef DEBUG
  2386.     cmn_err(CE_NOTE,"***-> putchar: Outputing: %x [%c]", c, 
  2387.                 (c =='\n' || c == '\r')? '.':c);
  2388.     #endif /* DEBUG2 */
  2389.  
  2390.     OUTB(addr+THR,c);
  2391. }
  2392.  
  2393.  
  2394. /**************************************************************************
  2395.  *                c o m t r o l _ h 5 5 0 _ g e t c h a r                 *
  2396.  **************************************************************************
  2397.  *
  2398.  *     Name:    comtrol_h550_getchar
  2399.  *
  2400.  *     Description:
  2401.  *        Get a character from a port and append status 
  2402.  *        to the data.
  2403.  *
  2404.  *     Returns:   -1 if no character received.
  2405.  *
  2406.  **************************************************************************
  2407. */
  2408.  
  2409. static int
  2410. comtrol_h550_getchar( h550port_t   *dp )
  2411. {
  2412.     volatile caddr_t addr;
  2413.     uchar_t           lsr_val;
  2414.     uchar_t          rbr; 
  2415.  
  2416.     addr = dp->port_addr;
  2417.     lsr_val = INB(addr+LSR);
  2418.  
  2419.  
  2420.     if (lsr_val & DR) {
  2421.         /* read possible error status */
  2422.         if (lsr_val &= (FE | OE | PE) ) {
  2423. #ifdef DEBUG2
  2424.             if ( lsr_val & FE )
  2425.                 cmn_err(CE_WARN, "!Framing error on serial port %d",
  2426.                     dp->dp_index);
  2427.  
  2428.             if ( lsr_val & OE )
  2429.                 cmn_err(CE_WARN, "!Overrun error on serial port %d",
  2430.                     dp->dp_index);
  2431.  
  2432.             if ( lsr_val & PE )
  2433.                 cmn_err(CE_WARN, "!Parity error on serial port %d",
  2434.                     dp->dp_index);
  2435. #endif    /* DEBUG2 */
  2436.         }
  2437.  
  2438.         if (dp->dp_state & DP_BREAK_ON)
  2439.             lsr_val |= BI;   
  2440.  
  2441.         /*
  2442.          * return Line Status Register value (as upper 8 bits)
  2443.          * and received character 
  2444.          */
  2445.         rbr = INB(addr+RBR);
  2446.         #ifdef DEBUG 
  2447.         cmn_err(CE_NOTE, 
  2448.         "***-> getchar: LSR = %x, Received Char: %x [%c]", lsr_val,
  2449.         rbr, (rbr =='\n' || rbr == '\r')? '.':rbr);
  2450.         #endif 
  2451.  
  2452.         return ( lsr_val << 8 | rbr );
  2453.     }
  2454.     else
  2455.         return(-1);
  2456. }
  2457.  
  2458.  
  2459.  
  2460. /**************************************************************************
  2461.  *                c o m t r o l _ h 5 5 0 _ s t o p _ t x 
  2462.  **************************************************************************
  2463.  *
  2464.  *     Name:    comtrol_h550_stop_tx
  2465.  *
  2466.  *     Description:
  2467.  *        Stop transmission on a port.
  2468.  *
  2469.  *     Returns:
  2470.  *
  2471.  **************************************************************************
  2472. */
  2473. static void
  2474. comtrol_h550_stop_tx(h550port_t *dp)
  2475. {
  2476.     volatile caddr_t addr;
  2477.     int         s;
  2478.     uchar_t         b;
  2479.  
  2480.     addr = dp->port_addr;
  2481.     s = LOCK_PORT(dp);
  2482.  
  2483.  
  2484.     b = INB(addr+IER);
  2485.  
  2486.     #ifdef DEBUG2
  2487.     cmn_err(CE_NOTE,
  2488.         "stop_tx: Stop transmit routine, IER before: %x", b);
  2489.     #endif /* DEBUG2 */
  2490.  
  2491.     b &= ~ETBEI;
  2492.     OUTB(addr+IER, b);
  2493.  
  2494.     UNLOCK_PORT(dp,s);
  2495.  
  2496. }
  2497.  
  2498.  
  2499.  
  2500.  
  2501. /**************************************************************************
  2502.  *           c o m t r o l _ h 5 5 0 _ s t a r t _ t x                       *
  2503.  **************************************************************************
  2504.  *
  2505.  *     Name:    comtrol_h550_start_tx
  2506.  *
  2507.  *     Description:
  2508.  *        Enable port for transmission (start transmission).
  2509.  *
  2510.  *     Returns:
  2511.  *
  2512.  **************************************************************************
  2513. */
  2514.  
  2515. static void
  2516. comtrol_h550_start_tx( h550port_t   *dp )
  2517. {
  2518.     volatile caddr_t addr;
  2519.     uchar_t             b;
  2520.  
  2521.     addr = dp->port_addr;
  2522.  
  2523.     /* if the boards outputs are not enabled, enable them */
  2524.     b = INB(addr+MCR);
  2525.  
  2526.     #ifdef DEBUG2
  2527.     cmn_err(CE_NOTE, "start_tx: MCR = %x", b);
  2528.     #endif
  2529.  
  2530.     if ( !(b & OUT2) ) {
  2531.         OUTB( (addr+MCR), b | OUT2);
  2532.         #ifdef DEBUG2
  2533.         cmn_err(CE_NOTE, "start_tx: Enabling Board Output-2, MCR=%x",
  2534.              b | OUT2);
  2535.         #endif
  2536.     }
  2537.  
  2538.     /*
  2539.      * if transmit interrupts are not enabled, enable them
  2540.      * and transmit one character to prime the pump 
  2541.      */
  2542.     b = INB(addr+IER);
  2543.  
  2544.     #ifdef DEBUG2
  2545.     cmn_err(CE_NOTE, "start_tx: board IER = %x", b);
  2546.     #endif
  2547.  
  2548.     if ( !( b & ETBEI) ) {
  2549.         OUTB((addr+IER), b | ETBEI);
  2550.         #ifdef DEBUG2
  2551.         cmn_err(CE_NOTE, "start_tx: Enablin Transmit Intr, IER = %x",
  2552.              b | ETBEI );
  2553.         #endif 
  2554.         h550_tx(dp,1);        /* send something (1 char) */
  2555.     }
  2556. }
  2557.  
  2558.  
  2559. /**************************************************************************
  2560.  *            c o m t r o l _ h 5 5 0 _ s t o p _ t x                        *
  2561.  **************************************************************************
  2562.  *
  2563.  *     Name:    comtrol_h550_stop_tx
  2564.  *
  2565.  *     Description:
  2566.  *        Stop the receive process.
  2567.  *
  2568.  *     Returns:
  2569.  *
  2570.  **************************************************************************
  2571. */
  2572. static void
  2573. comtrol_h550_stop_rx( h550port_t    *dp,
  2574.               int        hup )
  2575. {
  2576.     volatile caddr_t addr;
  2577.     int s;
  2578.     uchar_t        b;
  2579.  
  2580.     addr = dp->port_addr;
  2581.  
  2582. #ifdef DEBUG2
  2583.     cmn_err(CE_NOTE,"stop_rx: Stop receive routine");
  2584. #endif /* DEBUG2 */
  2585.  
  2586.     /*
  2587.      *    deassert RTS, DTR if hup != 0 
  2588.      *    deassert output handshake signals on tty port
  2589.      */
  2590.     if (hup) {
  2591.         s = LOCK_PORT(dp);
  2592.         /***  changed the following line  
  2593.                 OUTB(addr+MCR, INB(addr+MCR) & ~(DTR & RTS));
  2594.         ****/
  2595.         b = INB(addr+MCR);
  2596.         b &= ~(DTR | RTS);
  2597.         OUTB(addr+MCR, b);    
  2598.  
  2599.         #ifdef DEBUG2
  2600.         cmn_err(CE_NOTE, "stop_rx: hup, set MCR to: %x", b);
  2601.         #endif
  2602.  
  2603.         UNLOCK_PORT(dp,s);
  2604.     }
  2605.  
  2606.     /*
  2607.      * disable interrupt to the board 
  2608.      */
  2609.     s = LOCK_PORT(dp);
  2610.     b = INB(addr+MCR);
  2611.     b &= ~OUT2;
  2612.     OUTB(addr+MCR, b);
  2613.     
  2614.     #ifdef DEBUG2
  2615.     cmn_err(CE_NOTE, "stop_rx: Disabling Int, MCR = %x", b);
  2616.     #endif
  2617.  
  2618.     UNLOCK_PORT(dp,s);
  2619. }
  2620.  
  2621. /**************************************************************************
  2622.  *           c o m t r o l _ h 5 5 0 _ s t a r t _ r x                       *
  2623.  **************************************************************************
  2624.  *
  2625.  *     Name:    comtrol_h550_start_rx
  2626.  *
  2627.  *     Description:
  2628.  *        Start the receive process.
  2629.  *
  2630.  *     Returns:  !0 if Carrier detected
  2631.  *
  2632.  **************************************************************************
  2633. */
  2634. static int
  2635. comtrol_h550_start_rx( h550port_t    *dp )
  2636. {
  2637.     volatile caddr_t addr;
  2638.  
  2639.     uchar_t iir_val, msr_val;
  2640.     uchar_t mcr_val, ier_val;          
  2641.     uchar_t temp;
  2642.  
  2643.     addr = dp->port_addr;
  2644.  
  2645.     mcr_val = INB(addr+MCR);
  2646.     ier_val = INB(addr+IER);
  2647.  
  2648.  
  2649.     #ifdef DEBUG2
  2650.     cmn_err(CE_NOTE,"start_rx:  MCR = %x, IER = %x", mcr_val, ier_val); 
  2651.     #endif /* DEBUG2 */
  2652.  
  2653.  
  2654.     /* assert DTR and RTS and enable board outputs  */
  2655.     mcr_val |= (DTR | RTS | OUT2);
  2656.     OUTB(addr+MCR, mcr_val);
  2657.  
  2658.     #ifdef DEBUG2
  2659.     cmn_err(CE_NOTE, "start_rx: set DTR, RTS and OUT2, new MCR = %x",
  2660.         mcr_val );
  2661.     #endif
  2662.  
  2663.     /* watch carrier-detect only if this is an open modem port */
  2664.     if ( !(dp->dp_cflag & CLOCAL) &&
  2665.           (dp->dp_state & (DP_ISOPEN | DP_WOPEN)) ) {
  2666.      
  2667.         if (dp->dp_state & DP_FLOW) {
  2668.             ier_val |= (ERBFI | ELSI | EDSSI);
  2669.             OUTB(addr+IER, ier_val);
  2670.  
  2671.             #ifdef DEBUG2
  2672.             cmn_err(CE_NOTE, 
  2673.             "start_rx: set ERBFI, ELSI, EDSSI, new IER = %x", 
  2674.             ier_val);
  2675.             #endif
  2676.         }
  2677.     }
  2678.  
  2679.     else {
  2680.               ier_val |= (ERBFI | ELSI); 
  2681.               OUTB(addr+IER, ier_val);
  2682.  
  2683.               #ifdef DEBUG2
  2684.               cmn_err(CE_NOTE, 
  2685.               "start_rx: set ERBFI, ELSI, new IER = %x", ier_val);
  2686.               #endif
  2687.  
  2688.           OUTB(addr+IER, ier_val | (ERBFI | ELSI));
  2689.     }
  2690.  
  2691.     /* if now enabling input and there are no pending
  2692.      * receive interrupts, gobble old stuff  
  2693.      */
  2694.     iir_val = INB(addr+IIR);
  2695.     #ifdef DEBUG2
  2696.     cmn_err(CE_NOTE, "start_rx: IIR = %x", iir_val );
  2697.     #endif
  2698.  
  2699.     if (!(iir_val & (RDATA_AVAIL | RLINE_STAT))) {
  2700.         #ifdef DEBUG2
  2701.         cmn_err(CE_NOTE, "start_rx: clearing old data");
  2702.         #endif
  2703.         h550_rclr(dp); 
  2704.     }
  2705.  
  2706.     temp = INB(addr+LSR) & BI;
  2707.     if (temp) {    /* receiving break ? */
  2708.         dp->dp_state |= DP_BREAK_ON;
  2709.     }
  2710.  
  2711.     else {
  2712.         dp->dp_state &= ~DP_BREAK_ON;
  2713.     }
  2714.  
  2715.     msr_val = INB(addr+MSR);
  2716.  
  2717.     #ifdef DEBUG2
  2718.     cmn_err(CE_NOTE, "start_rx: MSR = %x", msr_val);
  2719.     #endif
  2720.  
  2721.     if (msr_val & CTS) {
  2722.         #ifdef DEBUG2
  2723.         cmn_err(CE_NOTE, "start_rx: CTS on");
  2724.         #endif
  2725.         dp->dp_state |= DP_CTS;
  2726.     }
  2727.     else {
  2728.         #ifdef DEBUG2
  2729.         cmn_err(CE_NOTE, "start_rx: CTS off");
  2730.         #endif
  2731.         dp->dp_state &= ~DP_CTS;
  2732.     }
  2733.  
  2734.     if (msr_val & DCD) {
  2735.                 #ifdef DEBUG2
  2736.                 cmn_err(CE_NOTE, "start_rx: DCD on");
  2737.                 #endif
  2738.  
  2739.         dp->dp_state |= DP_DCD;
  2740.     }
  2741.     else {
  2742.                 #ifdef DEBUG2
  2743.                 cmn_err(CE_NOTE, "start_rx: DCD off");
  2744.                 #endif
  2745.  
  2746.         dp->dp_state &= ~DP_DCD;
  2747.     }
  2748.  
  2749.     return(dp->dp_state & DP_DCD);
  2750.  
  2751. }
  2752.  
  2753.  
  2754. /**************************************************************************
  2755.  *             c o m t r o l _ h 5 5 0 _ c o n f i g                         *
  2756.  **************************************************************************
  2757.  *
  2758.  *     Name:    comtrol_h550_config
  2759.  *
  2760.  *     Description:
  2761.  *        Port configuration.
  2762.  *
  2763.  *     Returns:
  2764.  *
  2765.  **************************************************************************
  2766. */
  2767.  
  2768. static void
  2769. comtrol_h550_config(h550port_t    *dp, 
  2770.             ushort_t      cflag, 
  2771.             struct termio *tp )
  2772. {
  2773.     volatile caddr_t addr;
  2774.     ushort_t temp, temp_lcr = 0;
  2775.     ushort_t delta_cflag;
  2776.     ushort_t time_constant;
  2777.     uchar_t        b;
  2778.     addr = dp->port_addr;
  2779.  
  2780.     delta_cflag = (cflag ^ dp->dp_cflag)
  2781.         & (CBAUD | CLOCAL | CSIZE | CSTOPB | PARENB | PARODD);
  2782.  
  2783.     if (tp)
  2784.         dp->dp_termio = *tp;
  2785.  
  2786.     dp->dp_cflag = cflag;
  2787.  
  2788.     #ifdef DEBUG2
  2789.     cmn_err(CE_NOTE,"config port routine");
  2790.     #endif /* DEBUG2 */
  2791.  
  2792.     /* 
  2793.      * always configures during open in case the last process set up 
  2794.      * the port to use the external clock and did not set it back to use
  2795.      * the internal BRG
  2796.      */
  2797.     if (delta_cflag || !(dp->dp_state & DP_ISOPEN)) {
  2798.  
  2799.         if ((cflag & CBAUD) == B0) {     /* hang up line if asked */
  2800.             h550_coff(dp);
  2801.             h550_zap(dp, HUPCL);
  2802.         } 
  2803.  
  2804.         else {
  2805.             /* reset the XMT and RCV FIFO's */
  2806.             /*****  changed as below 
  2807.                         OUTB(addr+FCR, INB(addr+FCR) & (RFIFO_RST|TFIFO_RST));
  2808.             *******/
  2809.             b = 0; 
  2810.             b |= (RFIFO_RST|TFIFO_RST);
  2811.             OUTB(addr+FCR, b); 
  2812.  
  2813.             /* set number of data bits */
  2814.             switch (cflag & CSIZE) {
  2815.              
  2816.                case CS5:
  2817.                 temp_lcr &= ~(WLS0 | WLS1);
  2818.                 break;
  2819.  
  2820.                case CS6:
  2821.                 temp_lcr |= WLS0;
  2822.                 temp_lcr &= ~(WLS1);
  2823.                 break;
  2824.  
  2825.                case CS7:
  2826.                 temp_lcr &= ~(WLS0);
  2827.                 temp_lcr |= WLS1;
  2828.                 break;
  2829.  
  2830.                case CS8:
  2831.                 temp_lcr |= (WLS0 | WLS1);
  2832.                 break;
  2833.             }
  2834.  
  2835.  
  2836.             /* set number of stop bits */
  2837.             temp = cflag & CSTOPB;
  2838.             if (cflag & CSTOPB)
  2839.                 temp_lcr |= STB;
  2840.             else
  2841.                 temp_lcr &= ~(STB);
  2842.  
  2843.             /* set parity and type (odd/even) */
  2844.             if (cflag & PARENB) {
  2845.                 temp_lcr |= PEN;
  2846.                 if (!(cflag & PARODD))
  2847.                     temp_lcr |= EPS;
  2848.             }
  2849.  
  2850.  
  2851.             /*
  2852.                  * set baud rate divisor registers based 
  2853.              * on value in baud rate table 
  2854.              *
  2855.              * First, enable read/write of baud rate 
  2856.              * divisor latches then write out LS byte,
  2857.              * write out MS byte,
  2858.              * then disable read/write of baud rate 
  2859.              * divisor latches 
  2860.              */
  2861.  
  2862.             OUTB(addr+LCR,INB(addr+LCR) | DLAB); 
  2863.             OUTB(addr+DLL,h550_baudtbl[cflag&CBAUD]&0xff); 
  2864.             OUTB(addr+DLM,h550_baudtbl[cflag&CBAUD] >> 8); 
  2865.             OUTB(addr+LCR,INB(addr+LCR) & ~(DLAB)); 
  2866.  
  2867.             /*
  2868.              * output Line Control settings to uart's
  2869.              * Line Control Register
  2870.              */
  2871.             OUTB(addr+LCR, INB(addr+LCR) | temp_lcr);
  2872.  
  2873.             /*
  2874.              * set temp to value of Interrupt Enable 
  2875.              * register with the first four
  2876.              * bits set to zero (i.e. disabled) 
  2877.              */
  2878.             temp = INB(addr+IER);
  2879.             temp &= ~(ELSI|ERBFI|ETBEI|EDSSI);
  2880.  
  2881.             /* output this info to the IER */
  2882.             OUTB(addr+IER,temp);  
  2883.  
  2884.             (void)comtrol_h550_start_rx(dp);
  2885.         }
  2886.     }
  2887. }
  2888.  
  2889.  
  2890. /**************************************************************************
  2891.  *          c o m t r o l _ h 5 5 0 _ i f l o w                           *
  2892.  **************************************************************************
  2893.  *
  2894.  *     Name:    comtrol_h550_iflow
  2895.  *
  2896.  *     Description:
  2897.  *        Flow control on a port.
  2898.  *
  2899.  *     Returns:
  2900.  *
  2901.  **************************************************************************
  2902. */
  2903.  
  2904. static void
  2905. comtrol_h550_iflow( h550port_t  *dp,
  2906.             int         send_xon,
  2907.             int         ignore_ixoff )
  2908. {
  2909.     volatile caddr_t addr;
  2910.     uchar_t mcr_val;
  2911.  
  2912.  
  2913.     addr = dp->port_addr;
  2914.     mcr_val = INB(addr+MCR);
  2915.  
  2916.     #ifdef DEBUG2
  2917.     cmn_err(CE_NOTE,"iflow: MCR = %x", mcr_val);
  2918.     #endif /* DEBUG2 */
  2919.  
  2920.  
  2921.     /*   if hardware flow control   */
  2922.     if (dp->dp_state & DP_FLOW) {    
  2923.  
  2924.         #ifdef DEBUG2
  2925.         cmn_err(CE_NOTE, "iflow: DP_FLOW");
  2926.         #endif
  2927.         if (send_xon && !(mcr_val & RTS)) {
  2928.             OUTB(addr+MCR, mcr_val |= RTS);
  2929.         } 
  2930.  
  2931.         else if (!send_xon && (mcr_val & RTS)) {
  2932.             OUTB(addr+MCR, mcr_val &= ~(RTS));
  2933.         }
  2934.     }
  2935.  
  2936.     if (!ignore_ixoff && !(dp->dp_iflag & IXOFF))
  2937.         return;
  2938.  
  2939.     else { 
  2940.         if (send_xon && dp->dp_state & DP_BLOCK) {
  2941.             dp->dp_state |= DP_TX_TXON;
  2942.             comtrol_h550_start_tx(dp);
  2943.         }
  2944.         else if (!send_xon && !(dp->dp_state & DP_BLOCK)) {
  2945.             dp->dp_state |= DP_TX_TXOFF;
  2946.             dp->dp_state &= ~DP_TX_TXON;
  2947.             comtrol_h550_start_tx(dp);
  2948.         }
  2949.     }
  2950. }
  2951.  
  2952.  
  2953.  
  2954. /**************************************************************************
  2955.  *            c o m t r o l _ h 5 5 0 _ b r e a k                         *
  2956.  **************************************************************************
  2957.  *
  2958.  *     Name:    comtrol_h550_break
  2959.  *
  2960.  *     Description:
  2961.  *        process Break for a port
  2962.  *
  2963.  *     Returns:
  2964.  *
  2965.  **************************************************************************
  2966. */
  2967. static void
  2968. comtrol_h550_break( h550port_t *dp, 
  2969.             int start_break )
  2970. {
  2971.     volatile caddr_t addr;
  2972.     uchar_t lcr_val;
  2973.  
  2974.     addr = dp->port_addr;
  2975.     lcr_val = INB(addr+LCR);
  2976.  
  2977.     #ifdef DEBUG2
  2978.     cmn_err(CE_NOTE,
  2979.         "break: LCR = %x, start_break = %x", lcr_val, start_break);
  2980.     #endif /* DEBUG2 */
  2981.  
  2982.     if (start_break)
  2983.         lcr_val |= BRK;
  2984.     else    lcr_val &= ~BRK;
  2985.  
  2986.     OUTB(addr+LCR, lcr_val);
  2987. }
  2988.  
  2989.  
  2990.  
  2991. /**************************************************************************
  2992.  *             S h o w P o r t I n f o                                    *
  2993.  **************************************************************************
  2994.  *
  2995.  *     Name:    ShowPortInfo
  2996.  *
  2997.  *     Description:
  2998.  *        Shows Port info for a given port.
  2999.  *
  3000.  *     Returns:
  3001.  *
  3002.  **************************************************************************
  3003. */
  3004. void
  3005. ShowPortInfo( ushort_t    ctl, 
  3006.           h550port_t  *dp )
  3007. {
  3008.  
  3009.     caddr_t   addr;
  3010.  
  3011.     addr = dp->port_addr;
  3012.  
  3013.     cmn_err(CE_NOTE,"%d[%d]:\tRBR\tIER\tIIR\tLCR\tMCR\tLSR\tMSR",
  3014.          ctl, dp->dp_index);  
  3015.  
  3016.     cmn_err(CE_NOTE,"\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x", 
  3017.         INB(addr+RBR), 
  3018.         INB(addr+IER), 
  3019.         INB(addr+IIR), 
  3020.         INB(addr+LCR), 
  3021.         INB(addr+MCR), 
  3022.         INB(addr+LSR), 
  3023.         INB(addr+MSR) );
  3024.  
  3025. }
  3026.  
  3027.  
  3028.  
  3029. /**************************************************************************
  3030.  *                       g e t M i n o r I n f o                          *
  3031.  **************************************************************************
  3032.  *
  3033.  *     Name:      getMinorInfo
  3034.  *
  3035.  *     Description:
  3036.  *        For a given device Minor number, this routine
  3037.  *        figures out the Controller and Port number and 
  3038.  *        sees if the port is used as a Modem or a Flow 
  3039.  *        Control.
  3040.  *
  3041.  *     Returns:
  3042.  *
  3043.  **************************************************************************
  3044. */
  3045.  
  3046. void
  3047. getMinorInfo ( minor_t       minor_no, 
  3048.            minorNumInfo_t   *minfo )
  3049. {
  3050.     short    ctl;
  3051.  
  3052.     bzero(minfo, sizeof(minorNumInfo_t) );
  3053.     if ( minor_no <= 7 ) {
  3054.         minfo->m_port  = minor_no;
  3055.         minfo->m_ctl   = 0;
  3056.         return;
  3057.     }
  3058.  
  3059.     minfo->m_port = minor_no % 8;
  3060.     ctl = minor_no / 8;   
  3061.  
  3062.     if ( ctl >= 4 ) 
  3063.         ctl = ctl % 4;
  3064.  
  3065.     minfo->m_ctl = ctl;
  3066.  
  3067.     if ( (minor_no >= 32) && (minor_no <= 63) ) {
  3068.         minfo->m_modem = 1;
  3069.     }
  3070.  
  3071.     if ( (minor_no >= 64) && (minor_no <= 95) ) {
  3072.         minfo->m_flow = 1;
  3073.     }    
  3074. }
  3075.  
  3076.